# Introduction Source: https://docs.borghq.io/getting-started/introduction Welcome to Odin, your security operations platform Odin is Borg Security's client platform. It shows your organisation's attack surface, tracks security findings across your assets, and hosts Mjolnir, our agentic AI pentest engine. Odin home dashboard showing security posture overview Odin home dashboard showing security posture overview ## What Odin includes Continuously discover and monitor your domains, subdomains, IPs, and APIs. Know what's exposed before attackers do. All security findings in one place, triaged by severity, linked to assets, with suggested remediation steps and a threaded discussion with our analyst team. Agentic AI whitebox pentesting. Mjolnir reads your source code, maps your attack surface, generates test cases, and executes them autonomously. Push findings directly to Linear, Jira, GitHub, or GitLab. Keep your security and engineering workflows in sync. ## How it works Odin is organised around your **workspace**, which holds your organisation's assets, findings, and pentest history. When you sign in, you land on the Home dashboard. The sidebar groups everything into four sections: * **General**: Home and a global Findings view * **Testing**: Pentests, PR reviews, and HackerOne * **Attack Surface**: Assets * **Workspace**: Integrations, Reports, Team, API Keys, Billing, and Organisation Settings ## Getting started Until GitHub is connected and a payment method is on file, a **Get started** card sits at the bottom of the sidebar with those two steps. Add your name and photo so teammates can identify you. Use the sidebar **Get started** card, or the **Finish setting up** card on Home. Open **Findings** to see what's already been reported. Open **Assets** to see what Odin has discovered about your organisation. Go to **Testing > PR Reviews** and enable reviews for the repositories you care about. If you're here specifically to set up a Mjolnir AI pentest, jump straight to the [Mjolnir overview](/mjolnir/overview). # Logging in Source: https://docs.borghq.io/getting-started/logging-in Sign in to Odin with email OTP, passkeys, Google, GitHub, or single sign-on Odin uses passwordless authentication. There is one continue screen: the same actions sign you in if you already have access, or start a pay-as-you-go workspace if you do not. ## Continue with email Go to [odin.borghq.io](https://odin.borghq.io), enter your email, and click **Continue with email**. You can also start with **Continue with Google** or **Continue with GitHub**. You'll receive an email from Odin containing a six-digit verification code. The code expires after a few minutes. On **Verify email address**, type the six-digit code into the two groups of three boxes. The code submits when all six digits are entered, or you can click **Continue**. If you don't see the email, check your spam folder. If this is your first time, Odin then asks you to create an organisation: a name and a primary domain. Use your company domain. Personal inboxes such as Gmail cannot be claimed as that domain. ## Sign in with a passkey If you've registered a passkey (fingerprint, Face ID, or a hardware security key), Odin uses it automatically, so there's no separate button to click. When you enter your email and click **Continue with email**, Odin checks for a passkey before it sends a code. If it finds one, your device prompts you to authenticate and the button reads **Waiting for passkey**. Confirm the prompt and you're signed in, without an email or code. If you cancel the prompt, have no passkey on that device, or your browser doesn't support passkeys, Odin emails you a six-digit code instead. On supported browsers, your saved passkey can also appear as an autofill suggestion on the email field, so you can sign in before clicking **Continue with email**. Passkeys are the fastest and most secure way to sign in. See [Profile & Security](/platform/profile) to set one up. ## Sign in with single sign-on If your organisation has [single sign-on](/platform/organisation-settings#single-sign-on) set up, there is no separate button. Enter your work email and select **Continue with email**. Odin recognises the domain and sends you to your identity provider to authenticate, then you come back signed in, without a code or a passkey prompt. This only applies to email addresses on a domain your Admins have bound to the connection. Everyone else keeps the usual passkey or one-time-code flow. ## Continue with Google or GitHub Instead of entering your email, you can click **Continue with Google** or **Continue with GitHub** and choose that account. Odin signs you in directly, without an email or code. The same access rules apply as with email: an existing organisation membership signs you in, a matching [domain join](/platform/organisation-settings) adds you to that workspace, and a new address creates a pay-as-you-go organisation. Unverified Google accounts are refused. The old sign-up URL redirects to this same continue screen. ## First time You do not need an invite to start a pay-as-you-go workspace. Continue with Google, GitHub, or email; after verification, create your organisation. If your company already uses Odin, an existing member can invite you, or **domain join** can let anyone with a matching work-email domain join automatically. Personal inboxes never join someone else's organisation that way. For Enterprise sales, the continue screen has a **Looking for Enterprise? Book a demo** link to the [demo request page](/getting-started/request-a-demo). That page is for talking to the Borg team, not a failure state for a missing account. The form also links to the [legal agreements](/getting-started/terms-of-service) and the [privacy policy](https://odin.borghq.io/legal/privacy). Accepting terms for your organisation still happens after you are signed in, as described on the terms page. ## Switching organisations If you belong to multiple organisations, switch between them using the organisation selector in the sidebar. Your session persists across switches, so you do not need to sign in again. # Micro Pentest Source: https://docs.borghq.io/getting-started/micro-pentest The free one-shot code pentest a new workspace starts with A Micro Pentest is the free run Odin gives a new self-serve workspace. Mjolnir reads one GitHub repository and reports the vulnerabilities it can verify in the code. Most runs finish in about four minutes. Starting a Micro Pentest from Odin is currently unavailable. Contact Borg if you need a preview run. [PR Reviews](/mjolnir/pr-reviews) remain available under **Testing**. Micro Pentest is for organisations that haven't bought a plan yet. If you signed up through sales or already have a plan, you won't see it. ## What you get * One Micro Pentest per organisation. It is also one per repository and one per sign-up domain, so a second workspace on the same domain can't run it again. * A 24-hour window from the moment your organisation is created. After that the workspace is limited to choosing a plan. * Code only. The run reads your repository; it doesn't send traffic at a running application, and it doesn't repeat on later commits. ## Running it Sign up, then Odin takes you to the setup screen. It has three steps and you can skip any of them. What you're building, what matters most right now, and your team size. Odin uses the answers to tailor your home view. They save as you pick them. **Connect a repo** runs the Micro Pentest. **Add a domain** maps your external attack surface instead. That is worth doing, but it isn't the pentest, and it leaves your free run unspent. Install the Odin GitHub App with read access, then choose a repository from the list. Odin scans its default branch, shown next to the name. Confirm that you're authorised to test it, then select **Start Micro Pentest**. If no repositories appear, the GitHub App has no access to any. Grant it access to a repository and reconnect. ### The domain path Adding a domain claims it for your organisation and starts asset discovery. The domain has to match your email address. Odin opens [Assets](/platform/assets), which fills in over the next few minutes as recon finds subdomains, IPs and services. ## Watching the run The run page follows five stages: cloning the repository, building the data-flow graph, identifying attack vectors, verifying exploitability, and writing findings. Counts appear beside each stage as the run reports them, including files indexed, input sources and dangerous sinks found, and how many attack categories are running. Leaving the page doesn't stop anything. Return to it from your home dashboard. ## Results When the run finishes you get a summary: verified findings, the count at the highest severity present, lines scanned, and the time it took to reach the first finding. Below that is the finding list, capped at three and limited to medium severity and above. Lower-severity issues are still produced but aren't surfaced. Open **Findings** for the full write-up on each one: description, exploit path, and a remediation patch. While you're on the trial the Findings page is scoped to this run and carries a **Micro Pentest scope** badge. A footer there counts the unverified candidate issues the run turned up but didn't confirm. A run can also end in one of these states: * **No high-confidence findings.** The scan found nothing it could verify in your repository. * **Trial budget reached.** The run hit its free budget before confirming anything. * **The scan didn't finish.** Something failed on our side. Select **Retry Micro Pentest** to run it again at no cost. You get two retries, and a retry never spends the trial a second time. A Micro Pentest runs once. Continuous scanning, live verification against a running application, and [scheduled assessments](/mjolnir/scheduled-assessments) all need a plan. Micro runs themselves can't be scheduled. # Quickstart Source: https://docs.borghq.io/getting-started/quickstart Get up and running with Odin in minutes This guide walks you through the first things to do after logging in to Odin for the first time. Until GitHub is connected and a payment method is on file, a **Get started** card at the bottom of the sidebar keeps those two steps in view. ## 0. Accept terms of service The first time your organisation uses Odin, an **Owner** must review and accept the platform agreements: the Master Services Agreement, the Data Processing Agreement, and the AI Services Addendum. This is a one-time step for the whole organisation. Non-Owner members see a notice until this is done. See [Terms of Service](/getting-started/terms-of-service) for details. ## 1. Complete your profile Click your avatar in the top-right corner and select **Profile**. Add your name and a photo. This helps your team identify who made changes and who's responsible for which findings. ## 2. Explore your attack surface Go to **Attack Surface > Assets** in the sidebar. This page lists everything Odin has discovered about your organisation's internet-facing footprint: domains, subdomains, IPs, and APIs. Odin attack surface assets view showing discovered domains and IPs If you've just signed up, asset discovery may still be running. Check back in a few minutes. ## 3. Review your findings Open **Findings** in the sidebar. Findings are security issues from your assets and pentest runs, sorted by severity. Use the severity filter to focus on **Critical** and **High** findings first. ## 4. Connect your integrations Go to **Management > Integrations** to connect your issue tracker. Odin supports Linear, Jira, GitHub, and GitLab. Once connected, findings can be pushed directly to your engineering workflow with one click. Push findings to Linear Push findings to Jira Push findings to GitHub Issues Push findings to GitLab Issues ## 5. Turn on PR reviews Go to **Testing > PR Reviews** and enable reviews for the repositories you care about. To run a full AI pentest, go to **Testing > Agentic whitebox**. Launch is enabled by the Borg team: use **Contact the team about agentic whitebox testing** to open Live Support if you do not have it yet. Read the PR review guide ## Need help? If you get stuck at any point, use **Live Support** in the Odin sidebar. We're here to help. # Requesting a demo Source: https://docs.borghq.io/getting-started/request-a-demo Book a working session with the Borg team, or send a demo request Odin's continue screen can start a pay-as-you-go workspace without an invite. **Request a demo** is for Enterprise sales: a working session on your stack with the Borg team. The demo page at [odin.borghq.io/auth/request-demo](https://odin.borghq.io/auth/request-demo) gives you two ways to do that: book a time directly with someone on the Borg team, or leave your details and let us come back to you. A demo is a working session on your own stack. We'll look at a few PR reviews, some pentesting and asset discovery against your code and assets, rather than walk through a canned demo environment. ## Booking a time Go to [odin.borghq.io/auth/request-demo](https://odin.borghq.io/auth/request-demo). You can also reach it from the continue screen: **Looking for Enterprise? Book a demo**. Under **Choose who to meet** you'll see the Borg team members who take demo calls, each with their role. Pick whoever fits what you want to discuss. A Cal.com booking window opens over the page with that person's availability. Choose a time and confirm. The booking window is embedded, so you stay on the Odin page. If your browser blocks the embed, the same profile links open the booking page in a new tab. ## Sending a request instead If none of the available times work, select **Can't find a time? Send us a few details** and a short form appears. * **Name**: required * **Company**: required * **Work email**: required, and it's where we'll reply * **Role**: optional * **What would you like to try?**: optional, up to 2,000 characters The page confirms the request once it's sent. You won't get an automated acknowledgement, so nothing arrives in your inbox until one of us replies to the address you gave. Booking a slot afterwards still works if a time opens up. Submitting the form means Borg may contact you about the enquiry. See the [privacy policy](https://odin.borghq.io/legal/privacy) for how we handle those details. ## When Odin sends you here A few special cases still land on this page. If you **Continue with Google** on an unverified Google account, Odin refuses the sign-in and sends you here. If [domain join](/platform/organisation-settings) would have added you but your organisation has used all its seats, the demo page opens with the form expanded and a note about the seat limit. An admin on your team can add seats, which is usually quicker than waiting on us. Use the form if you'd rather talk about a separate workspace. A missing account is not sent here. Continue with Google, GitHub, or email to create a pay-as-you-go organisation instead. ## If a request doesn't go through Each email address can send three demo requests an hour. Wait an hour, or book a slot directly instead. One of the required fields is empty or the email address isn't valid. The field with the problem is marked in red. The request reached us but delivery failed on our side. Try again in a few minutes; if it keeps failing, email [mail@borghq.io](mailto:mail@borghq.io) directly. ## After the demo Once your organisation is set up, you'll be invited by email and can sign in normally. How passkeys, email codes and Google sign-in work. What Odin covers once you're in. # Subprocessors Source: https://docs.borghq.io/getting-started/subprocessors Third-party services that process data on behalf of Borg Security Borg Security uses a limited set of third-party subprocessors to deliver the Odin platform. Each subprocessor is listed below with the data it processes and where it operates. You can view this information at any time at [odin.borghq.io/legal/subprocessors](https://odin.borghq.io/legal/subprocessors). ## Current subprocessors | Entity | System | Location | Purpose | | ------------------------------- | ---------------- | -------- | --------------------------------------------------------------------------------- | | Twilio Ireland Limited | SendGrid | USA | Email delivery for OTP codes, invitations, and notifications | | Resend, Inc. | Resend | USA | Delivery of public Odin demo requests to Borg | | Intercom R\&D Unlimited Company | Intercom | USA | In-app customer support chat and messaging | | Functional Software, Inc. | Sentry | EU | Error monitoring and debugging | | Google Cloud EMEA Limited | Google Cloud | EU | Core backend infrastructure and processing pipeline | | Cloudflare, Inc. | Cloudflare | EU/USA | CDN, DNS, WAF, and DDoS protection | | Vercel Inc. | Vercel | EU/USA | Web application hosting and deployment | | Anthropic PBC | Anthropic | USA | AI model provider for Mjolnir pentest analysis (transient processing, no storage) | | MongoDB, Inc. | MongoDB Atlas | EU | Primary application database | | ClickHouse, Inc. | ClickHouse Cloud | EU | Event streaming and observability analytics | | PostHog, Inc. | PostHog | EU | Product analytics and session replay (inputs masked) | | GitHub, Inc. | GitHub | USA | Repository integration and issue syncing | This list is also maintained at [odin.borghq.io/legal/subprocessors](https://odin.borghq.io/legal/subprocessors) and is updated as subprocessors are added or removed. For questions about data processing, contact [mail@borghq.io](mailto:mail@borghq.io). ## Related agreements When your organisation first signs in to Odin, an Owner must accept three agreements before using the platform: * **Master Services Agreement (MSA)**: the core service terms * **Data Processing Agreement (DPA)**: how Borg Security processes personal data * **AI Services Addendum**: additional terms for AI features like Mjolnir These documents are shown during the [terms of service acceptance](/getting-started/terms-of-service) flow on first login. # Terms of Service Source: https://docs.borghq.io/getting-started/terms-of-service Accept the platform agreements before using Odin Before your organisation can use Odin, an Owner must review and accept the platform's legal agreements. This is a one-time step that applies to the entire organisation. ## What you're agreeing to The acceptance covers three documents: * **Master Services Agreement (MSA)**: the core terms governing use of the Odin platform * **Data Processing Agreement (DPA)**: how Borg Security handles and protects personal data * **AI Services Addendum**: additional terms for AI features, including Mjolnir Links to each document are provided in the acceptance dialog. We recommend reviewing them before accepting. ## Who can accept Only an **Owner** of the organisation can accept the terms of service. This is because the acceptance is legally binding on behalf of the organisation. ## Acceptance flow Log in with your email or passkey as usual. If terms haven't been accepted yet, a dialog appears automatically. Read through the linked MSA, DPA, and AI Services Addendum. Check the confirmation box to acknowledge that you have authority to bind your organisation, then click **Accept and Continue**. ## What other members see If the terms haven't been accepted yet, non-Owner members see a notice explaining that the organisation's Owner needs to complete this step. They can view the agreement documents but cannot accept on behalf of the organisation. If you're a member and see this notice, ask your organisation's Owner to sign in and accept the agreements so your team can get started. ## Finding the agreements later The agreements stay available after acceptance, so there's no need to hold on to a copy of the dialog. You can reach them two ways: * **The `/legal` page** lists the MSA, DPA, and AI Services Addendum alongside the [Privacy Policy](/legal/privacy) and [Subprocessors](/getting-started/subprocessors) list. The three agreements open as PDFs; the policies open in the app. * **[Organisation Settings](/platform/organisation-settings#legal-and-agreements)** has a **Legal & Agreements** card with the same links. Both are open to every member, not only Owners. See which third-party services process data on behalf of Borg Security # Step 3: Code & Documentation Source: https://docs.borghq.io/mjolnir/code-and-docs/repositories Select repositories and upload supporting files for whitebox analysis In this step, you tell Mjolnir which of your repositories to analyse for this run, and optionally upload supporting documentation that gives Mjolnir more context about your application. ## Selecting repositories The dropdown is populated from the repositories you connected in [Step 1: Connect GitHub](/mjolnir/setup/connect-github). Select every repository that is directly involved in the scope of this test. **Maximum: 4 repositories per run.** All selected repositories should tie directly to the target URLs you defined in [Step 2: Scope & Connectivity](/mjolnir/setup/scope-and-connectivity). If a repo isn't involved in serving or supporting those URLs, leave it out. ### How many repos to include | Situation | What to select | | ----------------------------------------- | ----------------------------------- | | Single full-stack repo | Just that one repo (ideal) | | Separate frontend + backend | Both repos | | Frontend + backend + infrastructure (IaC) | All three | | Monorepo with multiple services | The monorepo. Mjolnir navigates it. | One repo is the simplest and most effective setup. If you have a separate frontend and backend, include both. Mjolnir correlates client-side routes with server-side handlers to find mismatches in access control. ### Why the 4-repo limit? Mjolnir performs deep analysis of every file in every selected repository. Beyond 4 repos, the analysis time increases significantly without proportional benefit. If your application spans more than 4 repos, prioritise the ones closest to your attack surface (backend API, auth service, core frontend). ### Branches and monorepo subdirectories For each selected repository, you can choose a specific branch (defaults to your repo's default branch) and, for monorepos, a subdirectory to scope Mjolnir to a single service. ## File uploads In addition to your source code, you can upload supplementary files that help Mjolnir understand your application's architecture, data model, and intended behaviour. The more context Mjolnir has, the more targeted and accurate the assessment. This step is optional — Mjolnir works from source code alone, but supporting docs almost always improve coverage. **Accepted formats:** `.json`, `.yaml`, `.yml` An OpenAPI spec is the most valuable thing you can provide beyond source code. It gives Mjolnir a structured map of your API endpoints, request/response schemas, authentication requirements, and parameter types, without inferring all of this from crawling. If you have one, upload it. If you have several (e.g. v2 and v3), upload all of them. Common locations in a project: * `openapi.json` / `openapi.yaml` in the root * `docs/api.yaml` * Auto-generated at `/api-docs` or `/swagger.json` at runtime (export it and upload the file) **Accepted formats:** `.pdf`, `.md`, `.txt`, `.docx` Any documentation that describes your application's architecture, data flows, or infrastructure topology. This helps Mjolnir understand the relationship between components, which is especially useful for microservice architectures where the attack surface spans multiple services. **Accepted formats:** `.json`, `.yaml`, `.pdf`, `.md` A description of your application's roles and what each one can and cannot do. This directly improves the quality of privilege escalation tests — Mjolnir can check whether every boundary in your permission model is actually enforced. Examples: * A table showing which roles can access which endpoints * A RBAC/ABAC configuration file * A narrative description of your permission model **Accepted formats:** `.pdf`, `.png`, `.md` Descriptions or diagrams of the key user flows in your application: signup, checkout, approval workflows, data export, and so on. This helps Mjolnir prioritise which flows carry the most business risk. Anything else you think would help. When in doubt, include it. Mjolnir will use what's relevant and ignore what isn't. ### How to upload Drag and drop files onto the upload area, or click to open a file picker. Each uploaded file shows its name, detected type, and size. Mjolnir auto-detects the document type but you can override the classification before launch. Remove any file with the trash icon before proceeding. Choose your plan tier. This step is skipped if your organisation already has an active plan. # Mjolnir Configuration Source: https://docs.borghq.io/mjolnir/configuration Turn on PR reviews per repository and review Mjolnir's full-scan setup The Pentest scope page is a read-only view of what a Mjolnir pentest works from: its targets, repositories and supporting documents. PR review repositories are switched on from the [PR Reviews](/mjolnir/pr-reviews) page instead. Open it from **Settings > Pentest scope** on the [Agentic whitebox](/mjolnir/runs) page, or from the command palette as **Pentest scope**. If you have more than one Mjolnir-configured pentest, use the pentest selector in the page header to switch between them. The full-scan sections are read-only. To change any of them, use the **Edit in Setup Wizard** button, which takes you back to the wizard with the current configuration loaded as a draft. The button appears only once a pentest has a Mjolnir configuration. ## PR Reviews The **PR Reviews** section lists every repository your connected [GitHub integration](/platform/integrations/github) can reach, each with a toggle. Turning a repository on is all it takes to start reviewing its pull requests. You don't need a full-scan configuration or a completed Mjolnir run first. If you have connected [Azure DevOps](/platform/integrations/azure-devops), a second **PR Reviews · Azure DevOps** section lists those repositories in the same way. Each row shows the repository name and the branch reviews run against. Switching a repository on expands its settings; collapse them again with the chevron to keep a long list readable. | Setting | Description | Default | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | | **Trigger mode** | Review when a PR is opened, or review on every push. In open-only mode, use the **Run Mjolnir Review** button for later commits. When reviewing every push, commits that arrive in quick succession collapse into one review of the latest | Review on PR open only | | **Blocking severity threshold** | Fail the GitHub Check on Critical only, High and above, Medium and above, or never block | Never block | | **Auto-suppression** | When the same finding pattern is dismissed across several PRs, create a [suppression rule](/mjolnir/suppression-rules) for it automatically | On | | **Auto-suppression threshold** | How many different PRs must dismiss a pattern before auto-suppression fires. The minimum is 2; a lower number is rejected and the field reverts | 3 | Every control saves as soon as you change it. The threshold field saves when you click away from it. In open-only mode, when new commits land after a review, Mjolnir updates its comment on the pull request with a **Run Mjolnir Review** button that links back to Odin, so you can run the next review without leaving GitHub. Learn how the PR review flow works end to end ## Targets The **Targets** section shows the primary target URL Mjolnir tests, plus any extra domains in scope. These come from [Step 2: Scope & Connectivity](/mjolnir/setup/scope-and-connectivity) of the setup wizard. ## Repositories The **Repositories** section shows the primary repository and any additional repositories Mjolnir analyses for this pentest, each with its branch and, where one is set, its subdirectory. These come from [Step 3: Code & Documentation](/mjolnir/code-and-docs/repositories). ## Documents If you uploaded supporting documents in [Step 3](/mjolnir/code-and-docs/repositories), they appear here so you can see what Mjolnir has on file. To replace them, use **Edit in Setup Wizard**. ## When nothing is connected yet With no Mjolnir configuration and neither GitHub nor Azure DevOps connected, the page shows a **Connect GitHub to enable PR reviews** card instead of the sections above. Installing the GitHub App from there lists your repositories and lets you turn reviews on without going through full-scan setup. The same card also sits above the sections whenever GitHub is not connected. Connecting needs the Member role or higher; Read only members are told to ask a colleague. # Domain Verification Source: https://docs.borghq.io/mjolnir/domain-verification/overview Prove ownership of the domains you're testing Domain verification is required only when the run includes live HTTPS URLs. A static analysis of connected repositories does not need it. When you add live URLs, you must verify that you own or are authorised to test those domains before launch. Prove the **registrable apex** with a DNS TXT or CNAME record — verifying `example.com` covers `api.example.com`, `app.example.com`, and any other subdomain. Distinct apexes (`example.com` and `other.io`) each need their own record. A file proof only covers the exact host it was published on. Once an apex is verified via DNS, you don't need to re-verify it for future runs. You can verify domains in four ways. The wizard will pick the most convenient one for your DNS setup automatically, but you can always switch tabs and use a different method. *** ## Method 1: One-click DNS (Domain Connect) If your DNS is managed by **Cloudflare** (or another [Domain Connect](https://www.domainconnect.org/)-supporting provider), Mjolnir can add the verification record for you. This is by far the fastest option. Mjolnir automatically detects whether your domain supports one-click setup. If it does, you'll see a panel offering **Continue to Cloudflare** (or **Continue** for other providers) above the manual verification tabs. The setup wizard opens your DNS provider's Domain Connect consent page in a new tab. Sign in to your DNS provider (e.g. Cloudflare) and approve the request to add the verification record. Mjolnir's apply URL is RSA-SHA256 signed so your provider can verify the request originates from Borg. You're redirected back to the setup wizard. Verification then runs automatically and the domain status flips to ✅ Verified within a few seconds. Mjolnir requests only the DNS records it needs for verification. It never asks for broader DNS or account permissions. If your domain's DNS provider doesn't expose a Domain Connect endpoint, this panel doesn't appear and you'll need to use one of the manual methods below. *** ## Method 2: TXT record Add a TXT record to your domain's DNS. | Field | Value | | ----- | ------------------------------------ | | Type | `TXT` | | Name | `_borg-verify.{your-domain}` | | Value | `borg-verify={your-generated-token}` | The exact values are generated for your organisation and shown in the setup wizard. Copy them directly from there. If your DNS provider doesn't support custom record names, you can place the TXT record on the root domain instead — Mjolnir will find it either way. TXT records typically propagate within a few minutes but can take up to 48 hours in rare cases. Most DNS providers update within 5–10 minutes. **Cloudflare users**: the wizard offers a one-click "Open Cloudflare DNS" link next to the TXT instructions that takes you straight to the DNS records page for your domain. *** ## Method 3: CNAME record Add a CNAME record to your domain's DNS configuration. | Field | Value | | ----- | -------------------------------------- | | Type | `CNAME` | | Name | `{your-generated-token}.{your-domain}` | | Value | `verify.borg.{your-generated-token}` | Both values are generated for your organisation — copy them from the wizard. **How to add a CNAME record:** 1. Go to your domain in the Cloudflare dashboard 2. Click **DNS > Records > Add record** 3. Set Type to `CNAME`, Name to the provided value, and Target to the provided value 4. Set Proxy status to **DNS only** (grey cloud). Proxied CNAME records won't resolve correctly for verification. 5. Click **Save** 1. Open the Route 53 console and go to **Hosted zones** 2. Select your domain and click **Create record** 3. Set Record type to `CNAME`, Record name to the provided value, and Value to the provided value 4. Click **Create records** 1. Log in and go to **My Products > DNS** 2. Click **Add** and select `CNAME` 3. Fill in the Name and Value fields with the provided values 4. Click **Save** *** ## Method 4: File upload Host a specific text file at a known URL on your domain. **Place the file at:** ```text theme={null} https://{your-domain}/.well-known/borg-verification.txt ``` **File contents:** ```text theme={null} {your-generated-token} ``` The file should be publicly accessible over HTTPS, return a `200` status code, and contain only the token (no extra whitespace or HTML). This method is useful if you don't have access to DNS but can deploy a file to your web server or CDN. *** ## Verifying Mjolnir polls each domain every few seconds while the step is open, so as soon as the record is in place the status flips automatically. You can also click **Retry** on any domain to check immediately. **Status indicators:** * 🔄 **Checking** — Mjolnir is looking for the record * ✅ **Verified** — record found and validated * ❌ **Failed** — record not found yet (try again after DNS propagation) Domain verification showing all checks passed If verification fails, double-check that: * You used the exact values shown in the wizard (copy-paste, don't retype) * DNS changes have had time to propagate (wait a few minutes and retry) * The file is accessible over HTTPS without a redirect If you're still having trouble, contact us at [mail@borghq.io](mailto:mail@borghq.io). *** ## After verification Once every apex domain in scope is verified, the **Run Assessment** button becomes active. Click it to launch Mjolnir. You'll be redirected to the live run dashboard, where you can watch the assessment as it runs. Domain verification persists. Once a domain is verified, you don't need to re-verify it for future runs against the same domain. File and CNAME proofs are for pentest authorisation only — [single sign-on](/platform/organisation-settings#single-sign-on) still needs a DNS TXT record. Publish that record on the organisation's Verified Domains card and select **Re-check**; the pentest proof stays in place if the TXT record is not there yet. # Mjolnir Overview Source: https://docs.borghq.io/mjolnir/overview Autonomous AI-powered whitebox pentesting Mjolnir is Borg Security's agentic AI pentest engine. It reads your source code, maps your application's attack surface, generates targeted test cases, and executes them autonomously, from end to end. ## What makes it whitebox Traditional automated scanners probe your application from the outside. Mjolnir starts from the inside, reading your source code to understand your routes, authentication flows, data models, and business logic before it ever sends a single request. This means it finds vulnerabilities that black-box tools miss: logic flaws, broken access controls, misconfigured authorisation chains, and authentication bypasses that only make sense once you understand the code behind them. ## How a run works A run moves through five phases, which the run dashboard tracks live on a phase stepper. Mjolnir reads the repositories you've connected, builds a map of your routes, middleware, data models, and authentication boundaries. Mjolnir crawls your application and cross-references what it finds with the code map to build a complete picture of the attack surface. Based on the attack surface, Mjolnir generates targeted test cases for each vulnerability category and queues them for execution. Test cases are executed against your target URLs. Mjolnir generates its own user contexts as it explores, so you don't need to supply test accounts. Confirmed findings are written up with severity ratings, reproduction steps, and suggested fixes, then pushed straight to your issue tracker if you have one connected. Mjolnir run dashboard showing live progress of a pentest run ## What Mjolnir tests for Mjolnir generates test cases across a broad range of vulnerability categories, including: Login bypasses, weak credential policies, session fixation, token leakage, and insecure password reset flows. Privilege escalation (vertical and horizontal), broken access controls, IDOR, and missing function-level checks. SQL injection, NoSQL injection, command injection, SSTI, and other server-side injection vectors. Sensitive data in responses, overly permissive API fields, PII leaks, and missing data redaction. ## Test users Mjolnir generates the user accounts and authentication contexts it needs on its own as it explores your application. For most applications, you don't need to provide test users. For enterprise customers with complex multi-step authentication flows — for example, multi-tenant onboarding sequences or workflows requiring a specific sequence of API calls — Borg's senior security engineers can manually inspect the application and prepare a tailored Mjolnir configuration that captures those flows. Contact us at [mail@borghq.io](mailto:mail@borghq.io) if you need this. Self-serve test-user supply for client-supplied accounts is coming. We'll update these docs when it ships. ## Pricing Your Borg subscription covers the full Odin platform: continuous asset discovery, findings management, issue tracker integration, and reporting. Your active plan grants recurring credits that are used for Mjolnir runs and CAD deductions. Mjolnir usage is deducted from credits based on your selected plan tier. If a Mjolnir run completes without confirming any vulnerabilities, you don't pay for it. See [Billing](/platform/billing) for tier details and how to activate. ## Setting up a run A Mjolnir run is configured through a five-step wizard: | Step | What you do | | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | | 1. [Connect GitHub](/mjolnir/setup/connect-github) | Grant Mjolnir read access to your repositories | | 2. [Scope & Connectivity](/mjolnir/setup/scope-and-connectivity) | Define target URLs and verify Mjolnir can reach them | | 3. [Code & Documentation](/mjolnir/code-and-docs/repositories) | Select repos and upload supporting files | | 4. Pricing | Choose your [plan tier](/platform/billing). Shown only if your organisation has no active plan, and no card is needed up front | | 5. [Review & Verify Domain](/mjolnir/domain-verification/overview) | Review configuration and prove domain ownership | Agentic whitebox launch is enabled by the Borg team for selected organisations. If it is not on yet, **Contact the team about agentic whitebox testing** opens Live Support in Odin. You are not asked to connect GitHub or visit integrations until launch is enabled. If your organisation doesn't have an active plan yet, launching takes you to **Stripe Checkout** to complete the purchase. Payment, billing address, and VAT/tax ID are all collected there. Your setup is saved as a draft, and you return to it automatically after checkout to launch the run. Drafts auto-save as you work, so you can come back to a setup at any time. Begin the Mjolnir setup wizard # PR Reviews Source: https://docs.borghq.io/mjolnir/pr-reviews Automatic and on-demand Mjolnir security reviews for pull requests PR Reviews are Mjolnir security reviews that run on your pull requests. They give you fast, targeted feedback during code review — before vulnerabilities are merged — rather than waiting for a full pentest run after deployment. Open the PR Reviews page from **Testing > PR Reviews** in the sidebar. PR Reviews work with both GitHub and Azure DevOps repositories. The reviews table stays on this page. If GitHub is not connected, or no repository has reviews on yet, a **Finish setting up** card sits above the empty table. **Connect GitHub** starts the GitHub App install. **Enable PR reviews** opens [Mjolnir Configuration](/mjolnir/configuration#pr-review), and the **Repositories** panel on this page lets you switch reviews on per repository without leaving it. You can also connect GitHub from the same card on [Home](/platform/home-dashboard#finish-setting-up), and request reviews on demand from GitHub comments. ## How it works When a pull request is opened (or pushed to, depending on your trigger mode), Mjolnir: 1. Receives the PR diff and metadata from GitHub 2. Reviews the changed code against the rest of your repository 3. Surfaces any new security issues introduced by the change 4. Posts the results back to GitHub as a Check run 5. Optionally fails the check if findings meet your blocking severity threshold Mjolnir's review is targeted at the diff. It analyses the specific code that's changing in the context of your codebase, so it can catch issues that only appear when the new code interacts with existing logic. ## Configuration PR review settings are per repository, not global. After GitHub is connected, the **Repositories** panel on the PR Reviews page lists every repository your GitHub App can reach. It opens automatically while no repository has reviews on, and collapses to a count once some do. Azure DevOps repositories appear in the same panel once that integration is connected. Turning a repository on expands its own set of controls: * **Trigger mode**: review on PR open only, or on every push * **Blocking severity threshold**: fail the check on Critical only, High and above, Medium and above, or never * **Auto-suppression**: when the same finding pattern is dismissed across multiple PRs on that repository, automatically create a [suppression rule](/mjolnir/suppression-rules) so it stops being raised * **Auto-suppression threshold**: how many distinct PRs must dismiss a pattern before auto-suppression kicks in ## The PR Reviews list The list view shows every PR review across your repositories. * **Filter** by repository or status (Queued, Running, Completed, Failed) * **Sort** by date or by number of open suggestions * **Click** any review to open its detail page Each row shows the PR title and branch, the repository, the open suggestion count, the status and conclusion, and when the review was opened. A summary bar above the table totals reviews, open suggestions, and reviews needing attention. An **Actions** column appears when a review on the page can be retried or has open suggestions: **Retry** for a failed review, or **Accept all** for open suggestions. ## Review detail The detail view shows everything Mjolnir found: * **PR summary**: title, author, repository, head SHA, links back to GitHub and the check run * **Diff stats**: files changed, lines added/removed * **Suggestions**: each issue Mjolnir raised, with its file, line range, and severity, plus a suggested code fix when Mjolnir is confident enough to propose one * **Status filters**: counts of open, accepted, and ignored suggestions, plus resolved and failed counts when either applies * **Mjolnir summary**: a high-level write-up of what Mjolnir saw in this PR ### Accepting or ignoring a suggestion For each open suggestion, your team can: * **Accept** the suggested fix. Mjolnir commits it directly to the PR's head branch and marks the suggestion **Accepted**. * **Ignore** the suggestion if it doesn't apply (the equivalent of "won't fix"), optionally with a reason. You can also accept every open suggestion in a review at once with **Accept all**, available from both the list and the detail page. To apply just some, select them with the checkboxes; they're committed together in a single commit. Accept is only available while the pull request is open and the head branch lives in the same repository as the base. Fork PRs cannot be applied from Odin — committing would write to your organisation's copy of the branch rather than the contributor's PR. Apply the fix on the fork, or merge the PR first. A suggestion can also land in two further states outside these actions. **Resolved on GitHub** covers a review thread resolved directly on GitHub rather than acted on in Odin (this stays distinct from Ignore, so it doesn't feed auto-suppression). **Failed** covers an accepted fix that couldn't be committed, for example because the file changed since Mjolnir read it. Ignoring suggestions feeds the auto-suppression system: if the same pattern is ignored across multiple PRs on that repository above your configured threshold, Mjolnir creates a [suppression rule](/mjolnir/suppression-rules) automatically so it stops being raised on future PRs. ### Correlated findings Mjolnir cross-references every PR review against the findings already tracked for your organisation. When a change touches a known finding, that result leaves the general Suggestions list and moves into one of two dedicated sections: * **Addressed Findings**: known findings this PR remediates. A quick way to confirm a fix landed where you expected. * **Regression Risk**: known findings this PR may make more exploitable. Worth a closer look before you merge. A correlated result that carries a suggested fix keeps its full card, with the diff and the **Accept** and **Ignore** actions, marked with a coloured edge to show the link. An informational correlation shows a compact card instead: the tracked finding's identifier, title and severity, plus a one-line verdict ("Addresses this finding" or "Worsens this finding"). Either card opens the finding in your [Findings](/platform/findings) view. Individual suggestions and observations can also carry an inline link to a related finding, labelled **Fixes**, **Worsens**, or **Related to**, when Mjolnir spots a connection that does not warrant its own section. ## Triggering a review manually If you want to ask Mjolnir to review a specific PR that wasn't auto-reviewed (or to re-review a PR after changes), there are two ways to do it: * **From GitHub**: when the Mjolnir GitHub App is installed, a "Run Mjolnir Review" button is available on the PR * **Direct link**: visit `/pentest/mjolnir/pr-reviews/trigger?repo=owner/repo&pr=123` in Odin (this is the URL the GitHub button calls) The trigger queues the review and redirects you to the detail page once it's ready. ### Re-running a failed review from GitHub GitHub can re-request the **Mjolnir Security Review** check directly from the pull request. Odin accepts native reruns for reviews in the **Failed** state, reuses the existing review and check run, and queues the same head commit again. Reviews that are already queued or running are left alone. Completed reviews cannot currently be rerun from GitHub. This prevents a second analysis of the same commit from replacing findings that have already been bridged into Odin. Use a new commit or the existing Odin retry action when the review itself failed. ### Ask from a pull-request comment You can also request an on-demand review directly from a GitHub pull request. Add a comment containing a real `@gungnirai` mention and the standalone word `review`, for example: ```text theme={null} @gungnirai, please review the latest changes ``` The command is case-insensitive and accepts punctuation between the mention and the request. It works even when automatic PR reviews are disabled, so you can keep automatic runs off and request reviews only when you need them. For safety, Odin accepts requests from repository owners, members, collaborators, or contributors who authored a commit in the pull request. Bot comments and unauthorised public comments are ignored. Odin also checks your organisation's entitlement and available credits before queuing the review; if a review cannot run, GitHub receives a neutral check with an explanation instead. Odin reviews each pull-request head commit at most once. Push a new commit before requesting another review after making changes. ## Trigger modes | Mode | Behaviour | | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | **Review on PR open only** | Automatically reviews when a PR is first opened. Use the "Run Mjolnir Review" button on subsequent commits. Best for keeping costs down. | | **Review on every push** | Automatically reviews on every push. If multiple commits arrive rapidly, only the latest is reviewed. Best for continuous feedback. | Manage patterns Mjolnir should not raise in PRs # Agentic whitebox Source: https://docs.borghq.io/mjolnir/runs Launch Mjolnir pentests and follow their progress The Agentic whitebox page is where you follow Mjolnir pentests and, once the Borg team has enabled it for your organisation, launch them. Open it from **Testing > Agentic whitebox** in the sidebar. Launch is not self-serve. The page stays visible so you can review past runs. Until the team enables agentic whitebox, launch actions and setup show **Contact the team about agentic whitebox testing** instead of Connect GitHub or integrations. That opens Live Support in Odin with a message ready to send. We turn it on from Operations. GitHub connect stays on **Testing > PR Reviews** for organisations that use reviews. The **Settings** menu in the header opens [Pentest scope](/mjolnir/configuration) and [Ignored findings](/mjolnir/suppression-rules). The **Pentests** heading counts your runs and how many are active or completed. Scheduled assessments appear above the list only once you have created one. ## Starting a run When agentic whitebox is enabled, **Launch a pentest** in the header opens the launch form: pick a repository, branch and folder, add a target URL, then launch. Organisations with an existing configured pentest also see **Run assessment**, which starts that pentest again after a confirmation dialog warning that the run can't be paused once started. A run cannot be paused once started. You can abort it, but the assessment then has to be restarted from the beginning. Only one run can be active at a time, so **Run assessment** is disabled while one is in progress. The empty run list offers **Launch a pentest** as well. Once you confirm, the run appears in the list with a progress bar that moves through the analysis, recon, planning, attack and report phases. Odin does not show agent logs. When the run completes, **View findings** on its card opens the Findings tab filtered to Mjolnir results, and **Download report** fetches the PDF once one exists. To repeat a run later instead of starting one now, use **Schedule** next to it. That button only appears once you have at least one completed run to schedule from. See [Scheduled assessments](/mjolnir/scheduled-assessments). ## Run statuses Each run has a status indicating where it is in its lifecycle: | Status | Meaning | | ------------- | ------------------------------------------- | | **Queued** | The run is waiting to be picked up | | **Running** | The assessment is actively in progress | | **Completed** | The run finished successfully | | **Failed** | The run encountered an error and stopped | | **Timed out** | The run exceeded its time limit and stopped | | **Cancelled** | The run was manually cancelled | Active runs display a **LIVE** badge in the run list. ## Run list Run history is a list of cards, one per run. Each card shows: * **Target domain**: the primary URL being assessed * **Repository**: the source code repository used * **Started**: when the run began * **Duration**: how long it ran * **Findings**: the number of findings discovered (once the run has a summary) Where a run covered more than one repository or domain, the card carries a `+2 repos` or `+1 domain` badge for the extras. If the run has a report, the card also has a download icon, so you can get the PDF without opening the run. Click any run to view its details. ## Run detail The detail header shows the target domain, when the run started, and how long it has been going. **Abort** sits there while the run is active, and **Download Report** once a report exists. A run that failed or timed out says so in a banner under the header. Where the run covered extra repositories or domains beyond the primary ones, a **Scope** panel lists them all as badges. Below that are three tabs: Overview, Findings, and Attack surface. ### Overview The overview shows the **phase stepper**, a visual timeline of where the assessment is in its pipeline: 1. **Analyse** — initial code analysis 2. **Map** — crawling your application and cross-referencing with source code 3. **Plan** — generating test cases from the attack surface 4. **Attack** — running test cases against your targets 5. **Report** — compiling confirmed findings into a report Below the phase stepper is a **live event feed** that streams events as they happen during an active run. Events include reconnaissance discoveries, test case execution, and finding confirmations. ### Findings Once a run produces findings, they appear in this tab with the same filtering and detail panel as the main [Findings](/platform/findings) page. The tab lists engine findings from this run together with any client tickets already on the pentest. You can filter by status, view full finding details, and export results. Client-ticket statuses can still be updated from the panel. Engine findings stay read-only until you **Promote to ticket**, which creates an organisation identifier so you can assign the issue, change status, and push it to your issue tracker. After promote, the engine row is replaced by the ticket. During an active run, this tab shows live finding cards as vulnerabilities are discovered in real time. ### Attack surface The Attack surface tab shows what Mjolnir discovered about your application and how much of it was tested. It populates live during a run — the technology stack appears first, during the initial code-analysis phase; endpoints then appear as reconnaissance finds them, and their coverage updates as the attack phase progresses — and stays available after the run completes. **Endpoints** lists every route Mjolnir found, with its method, path, whether authentication is required, known parameters, observed response codes, and a coverage pill: | Coverage | Meaning | | ------------ | ------------------------------------------------------------------------------------------------------------------------------ | | **Tested** | Mjolnir exercised the endpoint (whether or not it turned up a vulnerability) | | **Blocked** | Mjolnir was prevented from completing a test — for example by a WAF, an authentication wall, or the endpoint being unreachable | | **Untested** | No test targeted this endpoint | Use the filter buttons above the table to narrow it to a single coverage state. Alongside the table, two panels give context for the assessment: * **Technology stack** — the languages, frameworks, databases, and any high-risk dependencies detected in your code, plus the attack categories Mjolnir prioritised as a result. * **Defences observed** — the security controls Mjolnir saw while testing, such as WAF behaviour, Content-Security-Policy and CORS settings, security headers, and cookie flags. If no controls were observed, this panel says so. Until Mjolnir has learned anything about your application, the tab shows a "Mapping your attack surface…" placeholder; the technology stack is usually the first thing to appear. ## Aborting a run While a run is in the **Running** state, click the **Abort** button in the run detail header. The run is cancelled and its underlying job terminated. You can start a new run afterwards. ## Run summary When a run completes, a summary bar shows: * **Duration**: total time taken * **Total findings**: the number of vulnerabilities discovered * **Severity breakdown**: counts for Critical, High, Medium, and Low ## Downloading reports If a report was generated for a completed run, click **Download Report** in the run detail header to export a PDF containing all findings, reproduction steps, and remediation guidance. Learn how Mjolnir works and what it tests for # Scheduled Assessments Source: https://docs.borghq.io/mjolnir/scheduled-assessments Repeat a Mjolnir assessment on a date you pick, or on a recurring interval A schedule re-runs a Mjolnir assessment for you, either once at a future date or on a repeating interval. It copies its settings from a run you have already completed, so the target, repository, branch, and scan options stay the same each time. Schedules live on the [Agentic whitebox](/mjolnir/runs) page, under **Testing > Agentic whitebox**. The **Schedule** button sits next to **Run assessment** in the header once you have a completed run, and existing schedules are listed above the run history in a **Scheduled assessments** section. ## What you need first * **A completed full pentest run.** The Schedule button only appears once at least one run has finished. Micro Pentest runs cannot be scheduled. * **A member or admin seat.** Read-only members can view schedules but not create, edit, or delete them. * **An active plan.** Scheduling is plan-gated. Organisations with a manual Mjolnir grant are allowed through without a plan. ## Creating a schedule Click **Schedule** on the Runs page. The **Run configuration** dropdown lists your completed runs, each labelled with its target domain, repository, and date. Whichever you pick, its target, repository, and scan settings are saved with the schedule. **One time** asks for a date and time. **Recurring** asks for an interval: a number between 1 and 365, and a unit of days, weeks, or months. Click **Create schedule**. It appears in the Scheduled assessments list straight away, active by default. A run can only back one active schedule at a time. Creating a second one from the same run is rejected with "An active schedule already exists for this run". Edit or pause the first one instead. ### When the first assessment runs The two schedule types count from different starting points: * **One time** runs at the date and time you entered. The dialog rejects anything in the past. * **Recurring** waits one full interval before the first assessment. Set it to repeat every month and the first one starts a month from the moment you created the schedule, not immediately. The dialog spells this out under the interval fields. Editing a recurring schedule's interval restarts that count: the next assessment moves to one fresh interval from when you saved the change. Monthly intervals use calendar months and clamp to the end of a short month, so a schedule anchored on 31 January next runs on 28 February. ## What the schedule saves Creating a schedule takes a snapshot of the source run's configuration: repository and branch, web target and any extra domains, additional repositories, uploaded documents, model, attack categories, and time limits. Later edits to your Mjolnir setup do not reach an existing schedule, because the snapshot is what runs. To pick up new settings, complete a run with them and schedule that run instead. Repository credentials are the exception. GitHub installation tokens and Azure DevOps access tokens expire long before the next assessment is due, so a fresh one is minted at dispatch. If the underlying integration has been disconnected in the meantime, the dispatch fails and the schedule shows an error. ## Managing a schedule Each card in the Scheduled assessments list shows the target and repository, whether it runs once or on an interval, its next and last run times, and its time zone. Three controls sit on the right: * **The switch** pauses and resumes the schedule. A paused schedule keeps its settings but has no next run; resuming a recurring one sets the next assessment a full interval ahead. * **The pencil** opens **Customise schedule**, where you can move a one-time schedule's date or change a recurring one's interval. The source run cannot be swapped. * **The bin** deletes the schedule after a confirmation. Completed runs and their findings are not affected. ## Status badges A badge appears on the card when the last attempt did not start an assessment. | Badge | What happened | | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Paused** | The schedule is switched off and has no next run | | **Skipped overlap** | A run was already in progress for this pentest, so the recurring schedule moved on to its next interval | | **Deferred active run** | The same clash on a one-time schedule. Rather than lose the assessment, it retries in five minutes | | **Billing action needed** | The organisation could not start a credit-consuming run. A recurring schedule waits for its next interval; a one-time schedule retries in five minutes. The card's error line carries the specific reason | | **Creator unavailable** | The person who created the schedule left the organisation or was moved to read-only. The schedule is paused and needs recreating by a current member | | **Dispatch failed** | The assessment could not be published, most often because an integration has since been disconnected. The schedule retries in five minutes | Only one Mjolnir run can be active per pentest at a time, which is why an overlapping occurrence is skipped rather than queued. ## Time zones The schedule records the time zone of the browser you created it in, and the list formats its next and last run times in that zone. Editing from a different zone is fine. The dialog shows times in your current zone and names the zone the schedule was created in, so you can compare the two before saving. Follow an assessment once a schedule starts it # Allowlisting Borg IPs Source: https://docs.borghq.io/mjolnir/setup/allowlisting Let Mjolnir through your WAF or firewall Allowlisting is only needed for live URL tests. A static analysis of connected repositories does not send traffic to your application. If Mjolnir's connectivity check detects a WAF, rate limiter, or firewall blocking its requests, you'll need to add our IP ranges to your allowlist. ## Mjolnir IP ranges Add the following IP ranges to your allowlist: ```text theme={null} # Mjolnir egress IPs 104.199.11.56 104.199.76.78 35.240.97.28 34.52.178.160 ``` The current IP list is also provided during onboarding of Mjolnir. ## Platform guides 1. Log in to the Cloudflare dashboard and select your domain 2. Go to **Security > WAF > Tools** 3. Under **IP Access Rules**, click **Add a rule** 4. Set **Value** to each Mjolnir IP range 5. Set **Action** to **Allow** 6. Set **Zone** to apply to your specific domain (or all zones if needed) 7. Click **Add** Repeat for each IP range. If you're using Cloudflare's Bot Fight Mode or Super Bot Fight Mode, you may also need to create a **Configuration Rule** that bypasses bot detection for these IPs. 1. Go to the AWS Console > **WAF & Shield > IP sets** 2. Click **Create IP set** 3. Name it `mjolnir-allowlist`, select your region, and paste in the Mjolnir IP ranges 4. Go to your Web ACL > **Rules > Add rule > Add my own rules** 5. Select **IP set** and choose the set you just created 6. Set the action to **Allow** 7. Set the rule priority high enough to evaluate before any blocking rules Make sure the rule is set to **Allow**, not Count. If you're using Nginx's `limit_req` module to rate-limit requests, you can exempt Mjolnir's IPs using the `geo` module: ```nginx theme={null} geo $limit { default 1; # Mjolnir IPs (replace with actual ranges) 1.2.3.4/32 0; } map $limit $limit_key { 0 ""; 1 $binary_remote_addr; } limit_req_zone $limit_key zone=api:10m rate=10r/s; ``` Reload Nginx after making changes: `nginx -s reload` If your application is behind an AWS Security Group or NACL that restricts inbound traffic: 1. Go to **EC2 > Security Groups** and select the group attached to your application 2. Click **Inbound rules > Edit inbound rules** 3. Add a new rule for each Mjolnir IP range: * **Type**: HTTPS (or the appropriate port) * **Source**: Mjolnir IP range 4. Save the rules For Network ACLs, make sure both the inbound **allow** rule and the corresponding outbound rule for ephemeral ports are in place. ## After updating your allowlist Go back to the Mjolnir setup wizard and click **Re-run connectivity check**. The status for your URLs should update to ✅ Reachable. If you're still seeing issues after allowlisting, contact us at [mail@borghq.io](mailto:mail@borghq.io). There may be additional layers of protection we can help you identify. # Step 1: Connect GitHub Source: https://docs.borghq.io/mjolnir/setup/connect-github Grant Mjolnir read access to your repositories The first step in setting up a Mjolnir run is connecting your GitHub account. This gives Mjolnir read access to your source code, the foundation of the whitebox approach. Mjolnir only ever requests **read access**. It will never push code, open pull requests, or modify anything in your repositories. ## How to connect On **Home** or **Testing > PR Reviews**, click **Connect GitHub**. The row lives in the **Finish setting up** card. The Mjolnir setup wizard under **Testing > Pentests > Launch a pentest** offers the same button. You'll be redirected to GitHub to authorise the Odin Mjolnir GitHub App. Choose the GitHub organisation or account that owns your repositories. Select the repositories you want to make available to Mjolnir. You'll be redirected back to Odin. Your connected account will appear with a green checkmark. ## Selecting repositories After connecting, you'll see a list of repositories from your connected GitHub organisation. Select all repositories that belong to your organisation. Select the repositories Mjolnir should analyse for this run. The first selected repository is the primary repo; any others are included as additional context. ## Already connected? If you've previously connected GitHub (e.g. for another run), Odin shows your existing connection with the option to: * **Continue** with the current connection * **Switch account** to authenticate with a different GitHub account or organisation ## Troubleshooting GitHub App installations require explicit permission from a GitHub organisation owner. If you're not an org owner, ask your GitHub admin to approve the Odin Mjolnir app installation at `github.com/organizations/YOUR_ORG/settings/installations`. The GitHub App may have been installed with repository-scoped access rather than full org access. Go to your GitHub org settings > Installed GitHub Apps > Odin Mjolnir and update the repository access to **All repositories** (or add the specific ones you need). Close the tab and try again from the Mjolnir wizard. If the issue persists, contact us at [mail@borghq.io](mailto:mail@borghq.io). Continue — live URLs are optional # Setup Drafts Source: https://docs.borghq.io/mjolnir/setup/drafts Save and resume Mjolnir setup configurations Setting up a Mjolnir run involves connecting repositories, optionally adding live URLs, and reviewing the setup. Drafts let you save your progress and come back to it later, or maintain multiple configurations for different applications. ## Auto-saving Odin automatically saves your setup progress as you work through the wizard. You don't need to manually save — your current step, selected repositories, optional live URLs, and all other configuration is preserved automatically. If you close the browser or navigate away mid-setup, your draft is waiting for you when you return. ## Managing drafts When you start a new Mjolnir run, any existing drafts are shown before the setup wizard. From here you can: * **Resume** a draft to continue where you left off * **Rename** a draft to give it a descriptive label (e.g. "API v2 staging" or "Mobile app production") * **Delete** a draft you no longer need If you test multiple applications with Mjolnir, use draft labels to keep track of which configuration belongs to which app. Each draft stores its full setup state independently. ## What's saved in a draft A draft captures the full setup wizard state: * GitHub connection and selected repositories * Optional live URLs and custom headers * Connectivity check results (when live URLs are set) * Rate-limit bypass token configuration * Selected pricing tier * Domain verification status (when live URLs are set) * Current wizard step and progress When you resume a draft, you're returned to exactly where you left off, with all configuration intact. Learn how to launch and monitor pentest runs # Step 2: Scope & Connectivity Source: https://docs.borghq.io/mjolnir/setup/scope-and-connectivity Optional live URLs for a running application — static analysis does not need them Mjolnir analyses the repositories you selected in [Connect GitHub](/mjolnir/setup/connect-github) **statically by default**. You can continue this step without adding a URL. Add live HTTPS URLs only if you also want Mjolnir to test a running application. Live targets get a connectivity check and, at launch, domain verification. ## Static analysis (default) Leave the URL fields empty and click **Continue**. Mjolnir uses your connected source code. It does not send attack traffic to an application, and it does not need an allowlist. ## Optional: live target URLs Enter the URLs that make up a running application's scope. ```text theme={null} https://app.example.com https://api.example.com ``` You can add multiple URLs. Each one can have its own custom headers. Only add URLs you own and are authorised to test. Mjolnir will send real HTTP requests, including probes that may look like attack traffic, to everything in scope. ### Custom headers Each live URL can have custom HTTP headers attached. These are sent with every request Mjolnir makes to that URL. Common uses: | Header | Example value | Why | | ----------------------- | --------------------------------------- | --------------------------------------------------- | | Bypass rate limiting | `X-Internal-Token: abc123` | Stops your WAF from blocking Mjolnir's probes | | Route to staging | `X-Forwarded-Host: staging.example.com` | Points traffic to a test environment | | Auth bypass for testing | `X-Test-Mode: true` | Skips CAPTCHA or bot detection on test environments | Click **Add header** under any URL to add key/value pairs. If your application uses a WAF like Cloudflare or AWS WAF, allowlisting our IPs is usually more reliable than header bypasses. See [Allowlisting](/mjolnir/setup/allowlisting). ## Connectivity check (live URLs only) Once you've added at least one valid HTTPS URL, you can run the connectivity check. This takes a few seconds per URL. ### Status indicators | Status | Meaning | | ---------------------- | ----------------------------------------------------------- | | Reachable | Mjolnir can reach this URL without issues | | WAF detected / blocked | Requests are getting through but being flagged or throttled | | Unreachable | Mjolnir cannot reach this URL at all | ### If you see warnings or failures Add Mjolnir's IP ranges to your allowlist, then click **Re-run check**. Step-by-step instructions for Cloudflare, AWS WAF, and others You can proceed with remaining connectivity issues, but live coverage will be reduced. Static analysis of the selected repositories is unaffected. Review the setup. Domain verification is only required when you added live URLs. # Suppression Rules Source: https://docs.borghq.io/mjolnir/suppression-rules Stop the Mjolnir PR review agent from raising patterns you don't care about Suppression rules tell Mjolnir not to raise specific vulnerability patterns during [PR Reviews](/mjolnir/pr-reviews). Use them to mute false positives, accepted risks, or patterns that are intentional in your codebase (for example, raw HTML rendering in a static blog generator, or test code that purposely uses weak crypto). Open Ignored findings from **Settings > Ignored findings** on the [Agentic whitebox](/mjolnir/runs) page. ## Where rules come from Rules can be created two ways: * **Manual**: you create them on this page when you know a pattern shouldn't be raised * **Auto-learned**: when your team ignores the same suggestion across multiple PRs and you've enabled auto-suppression in [Mjolnir Configuration](/mjolnir/configuration#pr-review), Mjolnir creates a rule automatically once the threshold is hit Each rule shows its source so you can tell at a glance whether it came from the team or was learned from PR dismissals. ## Creating a rule Click **New Rule** (or press `c` from the page) to open the creation dialog. | Field | Description | | ---------------------- | ------------------------------------------------------------------------------------------------ | | **Scope** | Apply the rule to a single repository or across the entire organisation | | **Repository** | When scope is repository, the full `owner/repo` name from GitHub | | **Category** | The vulnerability category (e.g. `injection`, `authorisation`) | | **Vulnerability type** | The specific type within that category (e.g. `sql-injection`, `idor`) | | **File pattern** | Optional glob to restrict the rule to matching paths (e.g. `tests/**`, `src/legacy/*.ts`) | | **Reason** | Why this pattern is acceptable. This is required and gets shown to teammates reviewing the rule. | Use file patterns to scope rules narrowly. For example, suppress `sql-injection` only in `tests/**` rather than globally — that way Mjolnir still flags it in production code paths. ## Managing rules From the rules list you can: * **Filter** by source (Manual / Auto-learned) and status (Active / Disabled) * **Enable or disable** a rule with the toggle — disabling lets you pause a rule without losing it * **Delete** a rule permanently from the **Actions** column — Mjolnir resumes raising findings that match it on the next PR ## Best practices * **Document the reason** clearly. Future you (and your teammates) will thank you when reviewing why something was suppressed. * **Prefer narrow scope**: repository-scoped rules with file patterns are safer than organisation-wide rules. * **Review auto-learned rules** periodically. They're created from real dismissal patterns, but they can encode bad habits if your team is over-dismissing. * **Disable rather than delete** if you're not sure — disabled rules can be re-enabled later, deleted ones can't. # API Keys Source: https://docs.borghq.io/platform/api-keys Organisation-scoped programmatic access to Odin and the Odin MCP server API keys let your team interact with Odin programmatically — querying findings, assets, and pentests from scripts, CI pipelines, and AI agents like Cursor through the Odin MCP server. Open the API Keys page from **Workspace > API Keys** in the sidebar. Only admins and owners see this item. Only **Admin** and **Owner** roles can create or revoke API keys. Each key belongs to exactly one organisation. ## Creating an API key Go to **Workspace > API Keys** in the sidebar. The creation dialog opens with **Read & Write** selected for the remediation workflow. You can change it to **Read only** before creating the key. Give the key a descriptive name (for example, `Cursor MCP`, `CI Findings Sync`, or `Dashboard Export`). The name is visible only to your team. Use **Read only** when an agent should inspect data. Use **Read & Write** when it should update finding statuses or link an existing GitHub pull request after you explicitly ask it to. The full key is shown once and never displayed again. Copy it now and store it somewhere safe. The raw API key is shown only once. If you lose it, revoke the key and create a new one. Treat keys like passwords and never commit them to source control. ## Permissions | Permission | Scope | | ---------------- | --------------------------------------------------------------------------------------------------------------------------- | | **Read only** | Finding discovery, human-identifier remediation context, asset and pentest reads, GitHub PR suggestions, and retest history | | **Read & Write** | Everything above, plus client-supported finding status changes and linking an existing accessible GitHub pull request | A Read & Write key contains both read and write permissions. Server-side permission checks remain in force; choosing the default does not change existing keys or silently upgrade a Read-only key. For the remediation loop, ask the agent before every mutation. A matching identifier or pull-request URL is not permission to change Odin data. Odin never creates commits, pushes branches, or creates pull requests. ## Organisation scoping A key is permanently scoped to the organisation that created it. Odin resolves human finding references such as `ODI-12` only within that organisation and returns the canonical stored identifier. Findings, integrations, GitHub installations, and retest history from another organisation are not exposed. If you belong to multiple organisations, create one key per organisation and configure a separate MCP server entry for each (for example, `odin-acme` and `odin-internal`). This also makes revocation and audit attribution clear. ## Revoking a key To revoke a key, open **Actions** on its row, choose **Revoke**, and confirm. Any integration using that key stops working immediately. Revocation cannot be undone. ## Connecting an AI agent (MCP) The [Odin MCP server](/platform/odin-mcp) lets coding agents query your organisation's data through the Model Context Protocol. Once connected, you can ask an agent questions such as *"Explain `ODI-12` and show me the branch to create"*, then make the code change and open the PR yourself. Expand the **Setup guide: connect an AI agent** card on the API Keys page to see ready-to-paste configuration snippets for: * **Cursor** — add to `.cursor/mcp.json` or via Settings > MCP * **Claude Desktop** — add to `claude_desktop_config.json` * **Claude Code** — register from the terminal with `claude mcp add` * **Codex** — add to `~/.codex/config.toml` The snippets use the standard MCP stdio transport via `npx @borgresearch/odin-mcp@latest` with the key supplied as `ODIN_API_KEY`. Restart the client after changing its MCP configuration. After creating a key, the setup guide in the create dialog pre-fills the key into each snippet. Read-only keys remain appropriate for discovery, context, and retest reads; create a new Read & Write key for mutations. For the full tool reference, GitHub remediation flow, and troubleshooting, see [Odin MCP Server](/platform/odin-mcp). ## Calling the REST API directly If you'd rather make HTTP requests yourself, every API key works against the Odin REST API. Send the key as a Bearer token in the `Authorization` header. Keys always start with the `odin_` prefix: ```bash theme={null} curl https://odin.borghq.io/api/findings \ -H "Authorization: Bearer odin_your_key_here" ``` Requests are scoped to the organisation the key belongs to. A Read & Write key is required for any mutating endpoint, including status changes and manual GitHub PR linking. ### Human finding references The finding detail endpoint accepts either an internal finding ID or a human reference such as `ODI-12`. The prefix is an organisation-local alias; the numeric suffix is looked up only in the organisation identified by the key. Odin returns a non-enumerating 404 for malformed, unknown, invisible, or cross-organisation references. ### Interactive reference Odin ships an interactive API reference at [odin.borghq.io/api/docs](https://odin.borghq.io/api/docs). Sign in to the dashboard first, then open it to browse every public endpoint, see request and response shapes, and try calls from the page. The same spec is served as raw OpenAPI 3.1 at `/api/openapi.json` if you want to generate a client or import calls into Postman. ### Rate limits Each key is limited to **100 requests per minute** on a sliding window. When you exceed it the API returns `429 Too Many Requests` with a `Retry-After` header in seconds. ## Security notes * Treat API keys like passwords. Never commit them to source control or share them in chat. * Use one named key per integration or agent so you can revoke a single key if a machine or session is compromised. * Keys are scoped to a single organisation. They cannot access data from other organisations. * Manual PR linking verifies the URL through the organisation's GitHub App installation; Odin does not trust caller-supplied repository metadata or expose GitHub credentials. # Asset Relations Source: https://docs.borghq.io/platform/asset-relations Understand how your assets connect to each other Asset relations capture the connections between assets in your inventory — domain hierarchies, shared TLS certificates, and IPs serving multiple domains. They help you trace infrastructure dependencies, spot shared hosting, and understand the blast radius of any single asset. You'll see relations in the **Relation** tab on any asset's detail panel in [Assets](/platform/assets). ## Domain relations Domains and subdomains form a hierarchy: * **Root domain**: the top-level domain (e.g. `example.com`) * **Parent**: the domain one level up (e.g. `api.example.com` → `example.com`) * **Children**: subdomains beneath a domain (e.g. `example.com` → `api.example.com`, `app.example.com`) Walking these relations lets you see the full subdomain tree under any root domain. ## Certificate relations When multiple assets share the same TLS certificate (identified by SHA-256 fingerprint), Odin links them together. This is common with wildcard certificates or multi-domain (SAN) certificates. Certificate relations help you identify: * Assets served from the same infrastructure * Wildcard certificate coverage across your subdomains * Certificate-expiry risk affecting multiple assets at once ## IP relations IP relations connect assets that resolve to the same IP address. For each IP, Odin tracks: * **Domains**: every domain and subdomain resolving to this IP * **Open ports**: ports discovered during Network Recon * **Recon status**: whether Network Recon has been run against this IP Use IP relations to find shared infrastructure. If multiple domains resolve to the same IP, a vulnerability on one may affect all of them. ## How relations are derived Most relations are inferred automatically from recon data. DNS resolution, TLS certificate fingerprints, and reverse-DNS lookups feed the relation graph as [Continuous Asset Discovery](/platform/continuous-asset-discovery) scans run. You don't manage relations directly — they're a consequence of what Odin discovers about your attack surface. # Assets Source: https://docs.borghq.io/platform/assets View and manage your organisation's external attack surface Assets are your organisation's external attack surface — the domains, subdomains, and IPs that are visible from the internet. Everything Odin discovers via [Continuous Asset Discovery](/platform/continuous-asset-discovery), Mjolnir's reconnaissance phase, or that you add manually appears here. Open the Assets page from **Attack Surface > Assets** in the sidebar. ## Asset types | Type | Description | | ------------- | ----------------------------------------------------------- | | **Domain** | A root domain (e.g. `example.com`) | | **Subdomain** | A subdomain under a root domain (e.g. `api.example.com`) | | **IP** | An IPv4 or IPv6 address associated with your infrastructure | HTTP routes and endpoints are tracked separately and attached to the asset that serves them — see the **Routes** tab below. ## Sources Each asset is tagged with how Odin learned about it: * **Manual**: added by a member of your team * **Recon**: discovered by Continuous Asset Discovery * **Import**: added via CSV/JSON import * **Agent**: discovered by Mjolnir during a pentest run ## Adding assets There are two ways to add assets manually: * **Add asset**: click **Add Asset** in the page header, choose the type, and enter the value. You can also toggle Continuous Asset Discovery on at creation time. * **Import assets**: click **Import** and upload a CSV or JSON file containing multiple assets ## Activating Continuous Asset Discovery If your organisation has CAD enabled but hasn't yet activated a subscription, a banner on the Assets page prompts you to start. Once active, you can toggle CAD on a per-asset basis as you add or edit them. See [Continuous Asset Discovery](/platform/continuous-asset-discovery) for what CAD does and how it's billed. ## Asset detail Click any asset in the list to open the detail panel. The panel has five tabs: ### Overview Key metadata about the asset: * **Type, source, status, and creation date** * **DNS data**: A, AAAA, CNAME, and other resolved records (for domains and subdomains) * **HTTP data**: response status, headers, redirects (for domains and subdomains) * **TLS data**: certificate subject, issuer, expiry, and chain (for HTTPS endpoints) * **Open ports and services** (for IPs): each open port Odin found, with its detected service, web server, frameworks, and whether it supports TLS. When an IP sits behind an edge provider with nothing useful to scan, a note explains why no ports are listed (see [Infrastructure providers](#infrastructure-providers)) * **Notes**: a free-text field your team can edit; useful for owner / on-call info * **Monitoring toggle**: turn CAD on or off for this asset ### Tech Technologies detected on the asset — web frameworks, CMSes, JavaScript libraries, analytics tools, server software, and so on. Useful for understanding your supply chain and tracking inventory of risky dependencies. ### Relation A focused view of how this asset connects to other assets in your inventory: * **Domain hierarchy**: parent and child relationships in your domain tree * **Certificate sharing**: other assets that share the same TLS certificate * **IP co-resolution**: domains and subdomains resolving to the same IP See [Asset Relations](/platform/asset-relations) for more on how these connections are derived. ### Routes HTTP routes (paths and endpoints) Odin knows about for this asset. Click a route to open it, or use **Add route** to capture additional paths Odin hasn't yet seen — useful when you know about an endpoint that's not linked from any crawled page. ### Findings All findings that reference this asset, with the same filter, sort, and detail experience as the main [Findings](/platform/findings) page. ## Infrastructure providers When Odin recognises that an IP belongs to a known cloud or edge provider, it marks the asset with a provider badge. The badge shows in the assets list and in the detail panel header, so you can tell at a glance who owns an address range. Odin labels Cloudflare, Google Cloud, AWS, and Azure by name. A provider badge marks who owns the range, not whether Odin scanned it: * **Cloud compute** (AWS, Azure, and Google Cloud, including its global load balancers) is labelled and still fully port-scanned, so its open ports appear in the Overview tab as usual. * **Front-end edge ranges** (such as Cloudflare, CloudFront, and Front Door) host many customers behind shared addresses, so a port scan reveals nothing about your asset. Odin labels these and skips the scan. When that happens, the Open ports section shows a note saying the IP is edge infrastructure rather than a port list. A badge on its own never means scanning was skipped. The skipped-scan note appears only on an edge-provider IP that has no recorded open ports. ## Tree view The list is a domain tree, not a flat table. Subdomains sit under the closest parent that is already in the inventory (`staging.api.example.com` under `api.example.com`, then under `example.com`). When the parent domain is not in the current page, sibling hosts that share a root still group together. An IP nests under a hostname only when that hostname is the only loaded asset that resolves to it. Use the visibility control next to the filters: * **With findings**: show only assets that have findings. Parents needed to keep those assets in the tree stay visible, with a quieter name and metadata so they read as context rather than matches. Expand controls stay at full strength. Branches that lead to a finding stay open. * **Everything**: show every asset, including those with no findings. Switching to this view does not expand the tree — expand a row yourself when you want its children. You can still expand or collapse any row with the chevron. A red count marks how many assets in that branch have findings. The URL remembers the visibility mode, so you can bookmark either view. ## Filtering and search Use the filters at the top of the Assets page to narrow your view: * **Type**: show only domains, subdomains, or IPs * **Status**: filter by active, inactive, or unverified * **Source**: filter by Manual, Recon, Import, or Agent * **Search**: free-text search across asset names and metadata * **Sort**: order by value, last seen, or date added The URL updates as you filter, so any view can be bookmarked. Keyboard shortcuts: `j`/`k` navigate the visible rows, `Enter` opens the focused asset, `x` toggles selection. ## Exporting Click **Export** in the page header to download your assets in CSV, Markdown, or JSON. The export respects your current filters, so narrow the list first if you want a focused report. # Automatic Retests Source: https://docs.borghq.io/platform/automatic-retests Link a fix to a finding and let Odin verify it the moment your pull request merges Fixing a finding is only half the loop — someone still has to confirm the fix actually worked. Automatic retests close that loop for you: link the pull request that fixes a finding, and when it merges, Odin reviews the merged code change and decides whether the finding is resolved. There's no separate retest to request by hand, and the Odin MCP does not trigger a manual or paid retest. This sits at the end of the finding lifecycle, between **Mitigating** and **Fixed & Retested**. See [Finding status](/platform/findings#finding-status) for the full lifecycle. Automatic verification reviews the **merged code change**. A finding with no linked pull request can't be retested automatically — the merged diff is what the retest reads. ## Prerequisites Three things need to be in place for a retest to fire automatically: Install the Borg GitHub App so Odin can read your repositories and receive pull request events. See the [GitHub integration](/platform/integrations/github). On the GitHub card in **Management > Integrations**, enable **Automatic retests**. It's off by default, and when off, merging a fix updates the linked PR's state but doesn't trigger a retest. The toggle only appears once retests are available to your organisation — if you can't see it on the GitHub card, ask your Borg contact to enable them. The fix has to be connected to the finding. Odin can do this for you, or you can do it by hand — the options are covered next. ## Linking a pull request to a finding Every finding has a unique, human-readable identifier made from your [organisation's finding prefix](/platform/organisation-settings) and a sequence number — for example `BORG-12`. It's shown in the finding header and on every list row, and it's how Odin connects a finding to your engineering work. When the [GitHub integration](/platform/integrations/github) is connected, Odin watches incoming pull requests for a `{PREFIX}-{N}` identifier in three places, in priority order: 1. **The branch name** (highest priority) 2. **The pull request title** 3. **The pull request body** If a token matches a finding in your organisation, that PR is linked automatically. Odin re-scans when the pull request is opened, edited, reopened or closed — pushing new commits on its own doesn't re-scan, because the branch, title and body haven't changed. The source it matched on is recorded against the link, and you can see it in the **Link a pull request** dialog. Odin also keeps a **Linked Findings** comment on the pull request itself, listing each linked finding with its severity, status, discovery date and a link back into Odin. It edits that one comment in place rather than posting a new one on every event. There are three practical ways to make a link happen. ### 1. Copy the generated branch name (fastest) The finding detail header has a **Copy branch name** action. It gives you a ready-to-use git branch name that combines the identifier and a slugified title: ```text theme={null} fix/borg-12-sql-injection-in-login-form ``` Paste it into `git checkout -b`, push your fix, and open the PR — because the identifier is in the branch name (the highest-priority source), the PR links automatically the moment it's opened. This is the recommended path: nothing to remember, nothing to type. ### 2. Reference the identifier in the PR title or body If you branched some other way, just mention the identifier when you open the pull request. Any of these link the PR automatically: * A title like `BORG-12: fix SQL injection in login form` * A body that mentions the finding, such as `Fixes BORG-12` The same detection runs each time the PR is opened or edited, so adding the identifier to an existing PR links it too. ### 3. Link a pull request manually Sometimes a PR fixes a finding without mentioning it anywhere Odin looks. Choose **Link a pull request** from the finding's action menu to connect it by hand (needs the GitHub integration and permission to update the finding). The dialog lists recent pull requests, scoped to the finding's repository when Odin knows it, searchable by number, title, author, or branch. Pick one to link it, or paste a GitHub PR URL if it isn't in the list. Only manually linked pull requests can be removed. Unlink one from the dialog if you picked the wrong PR — auto-linked PRs are managed by Odin and would be re-created on the next PR event. ### Links Odin makes on its own from a PR review If your repository also runs [Mjolnir PR reviews](/mjolnir/pr-reviews), a completed review can link a pull request to a finding even when nothing in the branch, title or body mentions the identifier. The review reads the diff against findings Odin already knows about and records one of two relationships: * **Fixes** — the change addresses the finding. Odin links the PR and, if the finding is **Reported** or **Acknowledged**, moves it to **Mitigating**. The finding header shows an **Auto-linked by PR review** chip linking back to the review. * **Worsens** — the change makes the finding more exploitable. Odin links the PR, records a regression in the activity feed, and shows a **Regression risk** chip. If the finding had already reached **Fixed & Retested**, it's reopened as **Needs Revision**. Only the latest review counts. A redelivered or superseded review can't flip a relationship backwards or reopen a finding a newer review has since resolved. ### Linking through the Odin MCP The [Odin MCP server](/platform/odin-mcp) supports the same GitHub-first flow for coding agents. Ask the agent for `ODI-12` to get the remediation, suggested branch, workflow blockers, linked PRs, and latest retest state. Create the branch, commit, push, and open the pull request yourself in Cursor or your normal development environment. Then explicitly ask the agent to use `link_finding_pull_request` with the existing GitHub URL. The MCP verifies the URL through the organisation's GitHub App installation and stores the authoritative PR metadata. It does not create, modify, merge, or push the PR. Linking the same PR again is idempotent. A Read-only key can inspect context and read retest history with `get_finding_retests`, which never starts a retest or spends credits. Linking the PR or changing a finding status requires Read & Write. ### What linking does to the finding * **Linked PRs show as chips** in the finding header, one per pull request. Each chip shows the PR number and follows its state on GitHub: open, merged, or closed. Hover a chip for the title, repository, author and when it was linked. To see how a PR was linked, open the **Link a pull request** dialog. * **A PR linked to a Reported finding auto-transitions it to Mitigating**, a clear signal to Borg's analyst team that work is in progress. A finding already further along keeps its status — except a PR-review *fixes* link, which also advances an **Acknowledged** finding. * **Merging a PR does not, on its own, move the finding to Fixed & Retested.** In `develop → staging → production` workflows, merging to `develop` doesn't mean the fix is live. What the merge does trigger is the retest below. ## What happens when your PR merges When a pull request linked to a finding merges, and the finding is still retestable (Reported, Acknowledged, Mitigating, Open for Retest, or Needs Revision), Odin queues an automatic retest — provided **Automatic retests** is on for the GitHub integration, the organisation's retest automation capability is enabled, and the finding is eligible. A Mjolnir repository configuration is needed for live verification; code-analysis retests can use the merged GitHub diff without one. Odin then: 1. Checks out your repository at the **merge commit** 2. Extracts the code change the PR introduced (the diff between its base and head) 3. Reviews that change against the original finding — is the root cause actually addressed, is the fix complete, can it be bypassed, and does it introduce any regressions? The review looks past the symptom to the underlying cause (for example, SQL injection means checking for parameterised queries, not just that one string was escaped), and reads the surrounding files to confirm the fix holds across every code path. The retest reads a **snapshot of your code at the merge commit** to run the review, then discards it. It never writes to your repository — no commits, no comments, no pull requests. ## Retest outcomes A retest that runs to completion resolves to one of three outcomes: | Outcome | What it means | Finding status | | --------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------- | | **Fix verified** | The change addresses the root cause with confidence | Moves to **Fixed & Retested** | | **Fix is incomplete** | The change doesn't fully resolve the finding, or introduces a new issue | Moves to **Needs Revision**, with a comment explaining what's still wrong | | **Inconclusive** | The review couldn't confirm the fix either way | No status change — the finding stays where it was | **Fixed & Retested** is the one status only Borg can confirm. An inconclusive retest leaves the finding open so you can adjust the fix and merge again, or move it to **Open for Retest** for Borg's analyst team to verify by hand. Two more states mean no verdict was reached. **Retest skipped** means it never started, for one of the reasons listed below, and **Retest didn't complete** means something went wrong part-way. Both leave the finding's status alone, and both show on the retest detail with the reason. Neither puts a chip on the findings list. ## Following a retest You don't have to watch for the result — it surfaces across the Findings UI as it happens. * **In the findings list**, a chip appears next to the finding's title once it is in the retest workflow (**Mitigating**, **Needs Revision**, **Open for Retest**, or **Fixed & Retested**): **Retesting** while the review runs, then **Verified** or **Retest failed** once it completes. Reported and Acknowledged rows stay without a chip. * **On the finding detail**, a banner reports the same states — a fix being retested, a verified fix, or an incomplete fix that needs revision. On a finding sitting in **Open for Retest** with no result yet, the banner instead reads **Not retested yet** and offers a **See how** link. * **Click View retest** to open a dialog over Findings (not a separate page): * The outcome and the reasoning behind it * A **How this retest ran** timeline — the pull request that triggered it, followed by the code review step and its verdict * A **Spotted while retesting** section listing any related issues Odin noticed while reviewing the change, each with the file, line, and a short description Where there's no result to show yet, that same dialog gives you the generated branch name to copy and a button through to opening a pull request on the finding's repository. Close it with Escape, the close control, or by clicking outside. Issues in **Spotted while retesting** are observations attached to the retest, to give you a heads-up — they aren't raised as new findings automatically. Flag anything worth tracking to Borg's analyst team in the finding [discussion](/platform/findings#discussion-and-activity). ## When a retest doesn't run A retest is skipped, rather than run, when: * **The finding has no linked pull request** — there's no merged code change to review. Link a PR first. * **The PR was merged before it was linked** — linking a PR that's already merged doesn't retest retroactively. Move the finding to **Open for Retest** yourself when you're ready for Borg to verify it. * **Automatic retests is off** for the GitHub integration, or the finding is already **Fixed & Retested**. * **The finding is not in a retestable status.** Resume mitigation or use **Open for Retest** when the lifecycle requires a different verification path. * **A retest is already running** for that finding. One runs at a time, so a second merge while the first is still in flight doesn't queue another. * **Your organisation is out of credits** and auto-deposit is off. The retest is skipped and shown as such on the finding; top up or enable auto-deposit under [Billing](/platform/billing), then merge again or move the finding to **Open for Retest**. Connect GitHub and turn on Automatic retests Track findings through the full remediation lifecycle # Billing Source: https://docs.borghq.io/platform/billing Manage your subscription, payment methods, and invoices The Billing page lets admins manage your organisation's subscription, seats, credits, and invoices. Open it from the user menu in the top-right corner. It's organised into five tabs: **Overview**, **Plan**, **Credits**, **Usage**, and **Ledger**. Only **Admin** and **Owner** roles can manage billing. Other members can view billing information but cannot make changes. Organisations that buy credits directly instead of subscribing see a different page. See [Pay as you go](/platform/pay-as-you-go). If your organisation is on a trial plan, a banner at the top of the page shows the date your trial credits run out and lets an admin upgrade early. Once the trial ends, the banner prompts you to choose a plan instead. ## Overview The Overview tab shows your credit balance at a glance (plan credits remaining this period, adhoc credits, and any frozen adhoc credits), plus: * **Billing method**: whether you pay by card or invoice (Net 30), plus your billing email * **Total paid**: the cumulative amount paid across all invoices * **Outstanding**: any open invoices that haven't been settled yet Admins can update the billing email directly from the overview card. ## Plan Your subscription is plan-based. The active plan grants recurring credits used by Mjolnir runs and CAD deductions, and determines your seat allowance. ### Choosing a plan Plan purchases go through **Stripe Checkout**. Alongside payment details, Checkout collects your company's **billing address** and **VAT or tax ID** — these appear on your invoices and determine how tax is applied. Businesses in the EU that provide a valid VAT number are invoiced under the reverse-charge mechanism where applicable. Listed plan prices exclude VAT and sales tax. Any applicable tax is calculated at checkout from your billing address and tax ID, and shown before you confirm. ### Mjolnir AI-powered whitebox pentesting. Your active plan determines credit allowance, repository limits, and run allowances. You can change plans from the billing page. ### Seats Each plan includes a set number of seats, shown as a used-versus-available ratio. Pay-as-you-go organisations include five seats at no extra charge. Admins can: * **Invite members** directly from the card while seats are available * **Add seats**: buy extra seats at your plan's per-seat rate, billed on your next invoice and effective immediately * **Release unused seats**: reduce your extra-seat count once usage drops below the total, so the next invoice reflects fewer seats Both actions require [step-up verification](/platform/step-up-verification). Enterprise plans have custom seat terms and show a contact-your-account-manager message instead of the buy/release buttons. During a trial, seats work slightly differently: the buy/release buttons are hidden, and your seat allowance is managed by the Borg team — contact us if you need more trial seats. If you're using more seats than your plan includes when you subscribe, the card tells you how many extra seats will be added to your subscription at the plan's per-seat rate. The Seats card stays visible throughout the trial so you can track usage, and invites are blocked once your trial seat allowance is used. ### Payment methods If your billing method is **card**, you can add and manage payment cards here. Odin uses Stripe for payment processing, so your card details are never stored on our servers. * **Add a card**: click **Add card** and enter your details * **Remove a card**: click the remove icon next to any saved card Organisations on **invoice** billing (Net 30) don't see this section. ### Upcoming charges A line-item breakdown of your next invoice, showing each product, quantity, and amount. This updates as you add or remove products from your subscription. ### Invoices A table of all past invoices with: | Column | Description | | ---------- | ----------------------------------------- | | **Date** | When the invoice was issued | | **Status** | Paid, Open, Draft, Void, or Uncollectible | | **Amount** | The total billed | | **Period** | The billing period covered | You can download any invoice as a PDF or view it on Stripe's hosted invoice page. ## Credits ### Continuous Asset Discovery (CAD) Automated discovery and monitoring of your external attack surface, billed at **4 credits per monitored asset per month**, prorated daily. The **Continuous monitoring** card shows how many assets are currently monitored and the resulting monthly credit estimate. Admins can turn monitoring **on or off** for the whole organisation with the switch on this card: * **On** — your assets are scanned on their normal schedule and billed as above. * **Off** — monitoring stops and no CAD credits are charged. Your discovered assets are **kept** (they stay in your Assets inventory and map), so turning monitoring back on resumes where you left off. See [Continuous Asset Discovery](/platform/continuous-asset-discovery) for what CAD does. ### Auto Deposit Auto Deposit tops up your adhoc credit balance automatically from a saved card whenever it drops below a trigger you set, so usage-based work doesn't stall between plan renewals. When triggered, it makes a single charge sized to bring your balance back up to a target you choose. * **Below**: the balance, in credits, at or below which a top-up is triggered * **Top up to**: the target balance, in credits — one charge is sized to reach this target It charges the card already saved under **Payment methods**. Add a card there first if you don't have one. The card shows the estimated cost of each top-up before you save, based on your plan's adhoc credit rate (higher plans have cheaper adhoc credits). If a deposit fails (for example, an expired card), Auto Deposit pauses and the card shows an alert until you retry or update your payment method. Recent deposits are listed with their date, amount paid, and credits received. ### Frozen credits Cancelling your plan freezes any remaining adhoc credits rather than forfeiting them immediately. A frozen-credits card shows the balance and the six-month deadline to restore them. Reactivating any plan within that window unlocks the credits again; after it passes, they're lost. ## Usage The **Usage** tab is also a page of its own at `/billing/usage`. Opening it from the tab bar keeps you on that URL, so you can bookmark or share it. A chart of credit consumption over time, broken down by product (Mjolnir, PR Review, CAD, Cloud Review, Finding Retest, HackerOne Triage). Switch between daily and other granularities to see usage trends across the current billing period. ## Ledger A running log of every credit transaction: plan credits granted, adhoc credits purchased, deductions, expiries, refunds, and adhoc-credit conversions. Filter by type or product, and export the filtered results as a CSV. # Bug Bounty Triage Source: https://docs.borghq.io/platform/bug-bounty-triage Triage HackerOne reports before they reach your queue Bug bounty programs generate a lot of reports, and most of the work is deciding which ones are real. **HackerOne** in the sidebar is an inbox of your program's reports, each carrying a triage attempt to reproduce the issue against the live system it names. This page needs a connected HackerOne program. See the [HackerOne integration](/platform/integrations/hackerone) for the connect flow and asset mapping. Triage output is advice for your team. Your program stays the system of record. ## The inbox Every ingested report is a row, newest first. Press g b from anywhere to get here. | Column | What it shows | | --------- | -------------------------------------------------------------------- | | Report | Title, report number, the HackerOne asset, and the reported weakness | | Severity | The severity the reporter claimed, or **Unrated** | | State | The report's current state in HackerOne | | Triage | Where triage got to, or **Untriaged** | | Submitted | How long ago the hacker submitted it | Search by title or report number, and filter by state. The external-link icon on a row opens the report on HackerOne; clicking anywhere else opens it in Odin. Reports filed before the webhook was connected never arrive on their own. Paste a HackerOne report URL (or the numeric id) into the box at the top of this page and click **Triage**. Odin pulls the report with your Read only API token and queues a run if that asset is armed. ## Triaging a report Open a report and click **Triage now**, or paste a report URL on the inbox. The write-up is reproduced against the mapped live target and the result lands on the same page, so you don't need to keep it open. The button is unavailable in two cases: * **The asset isn't armed.** The report shows the exact asset string. Turn auto-triage on (or press **Triage now**) only after that asset has a live http(s) URL or a GitHub repo in [live targets](/platform/integrations/hackerone#program-assets-and-auto-triage). Nothing runs against a system you haven't authorised. * **A run is already going.** One run per report at a time, so a second click while one is queued or running is refused rather than starting a competing run. Once a run finishes, the button becomes **Triage again**. Re-triage after the reporter adds detail, or after you've deployed a fix and want to check the issue is actually gone. Every attempt is kept in **Run history** on the report, showing whether it was started by hand or by the webhook. Reports can also triage themselves as they arrive, per asset. See [auto-triage](/platform/integrations/hackerone#auto-triage). ## Reading the verdict A completed run gives a verdict, a confidence percentage, a severity, and a CWE, followed by an explanation of what the run did and what happened. | Verdict | Meaning | | ------------------- | ------------------------------------------------------------------------- | | Confirmed | Reproduced as described | | Partially confirmed | Part of the claim holds; the rest didn't reproduce | | Dormant | The weakness is present but not currently exploitable | | Needs prerequisites | Reproduction needs something the run didn't have, such as a valid account | | Not reproduced | The described behaviour didn't occur | | Needs review | The result isn't clear-cut and wants a human | | Not attempted | No reproduction was made | Depending on the verdict, the run may add: * **Reactivate if**: the condition that would make a dormant issue exploitable, so you know what to watch for. * **Dormant because**: why the weakness can't be exploited as things stand. * **Blocked**: what stopped the reproduction, when something did. * **Evidence**: the request and response from the run, plus proof-of-concept steps. Long evidence is marked as truncated. The hacker's own write-up and impact statement sit below, as submitted. Attachments and the comment thread stay on HackerOne. ## Report states The state column mirrors HackerOne: New, Pending review, Triaged, Needs more info, Resolved, Not applicable, Informative, Duplicate, Spam, and Retesting. Odin updates it when your program marks a report as triaged or closes it as resolved. Changing a state in Odin isn't possible. Do that in HackerOne and the inbox follows. ## Credits Each triage run consumes credits, billed by what the run costs to execute, and appears as **HackerOne Triage** in your [credit ledger and usage breakdown](/platform/billing). Re-triaging a report is a fresh run and is charged as one, which is worth keeping in mind before you turn auto-triage on for a busy asset. **Triage now** and auto-triage both need a ready billing account. If the prepaid balance is empty, Odin will not start the run — top up under [Billing](/platform/billing) first. A webhook still stores the report; only the automatic triage is skipped. # Changelog Source: https://docs.borghq.io/platform/changelog Follow new features, improvements, and fixes across Odin The Changelog is the public record of what's new in Odin. We post here whenever we ship a feature, fix a bug, or have an announcement worth sharing. Open it at [odin.borghq.io/changelog](https://odin.borghq.io/changelog). There's no sign-in, so you can share a link with anyone on your team. ## Browsing updates Entries are grouped by month, newest first. Anything we've pinned sits at the top under a **Pinned** heading so the updates we most want you to see don't scroll away. Each entry shows its title, a short summary, the date it went live, and one or more category tags. Click an entry to open its full page, where you'll find the complete write-up and, where we've recorded one, a short walkthrough video. Some entries are marked **Monthly summary**. These round up everything that shipped in a given month, which is handy if you'd rather skim one post than read each release individually. ## Filtering by category Every entry carries one or more tags. Use the pills at the top of the feed to narrow the list to a single category: | Tag | What it covers | | ---------------- | ---------------------------------------------- | | **Feature** | New capabilities added to the platform | | **Improvement** | Refinements to something that already existed | | **Fix** | Bug fixes and corrections | | **Security** | Security-relevant changes worth calling out | | **Announcement** | News that isn't tied to a specific code change | Select **All** to clear the filter and see everything again. ## Searching Use the search box to find a past update by keyword. The search matches against each entry's title, summary, and body, so you can track down a change even when you only remember roughly what it touched. Filtering by tag and searching work together: pick a category, then search within it. ## Sharing a specific update Open any entry and use the **copy link** action next to the date to grab a direct URL. Each entry has its own permalink, so you can drop it into a chat or ticket and link straight to the relevant update. ## Subscribing via RSS The changelog publishes an RSS feed at [odin.borghq.io/changelog/rss.xml](https://odin.borghq.io/changelog/rss.xml). Add it to your feed reader, or wire it into a Slack or Teams channel through your usual RSS connector, to get new entries as we publish them rather than checking the page by hand. Want a release flagged to your wider team automatically? Point an RSS-to-Slack (or RSS-to-Teams) connector at the feed above and new entries land in your channel as soon as they go live. # Connecting cloud accounts Source: https://docs.borghq.io/platform/cloud/accounts Give Heimdall read-only access to an AWS account, Azure subscription, or GCP project Cloud is currently unavailable in Odin. The Accounts page and connect wizard are parked. Contact Borg if you need a cloud account connected. **Cloud → Accounts** lists every cloud account connected to your organisation and is where you add new ones. Every connection is read-only: Heimdall reads your resource configuration and never changes it. ## Connecting an account Click **Connect account** to open the four-step wizard. Pick **Amazon Web Services**, **Microsoft Azure**, or **Google Cloud**. Changing provider later in the wizard clears everything you entered, so pick first. Give the connection a display name such as `Production`, then fill in the provider-specific fields: * **AWS**: your 12-digit account ID, plus the regions to scan. GovCloud and China regions are not offered, because Heimdall scans the standard partition only. * **Azure**: your Azure Active Directory tenant ID and the subscription ID to scan, both UUIDs. * **GCP**: the project ID to scan. Odin generates a ready-to-run template for your provider and shows the exact values it needs back: * **AWS**: a CloudFormation template that creates a read-only role trusting Borg's scanner. Deploy it from the console or the AWS CLI, then paste the stack's `RoleArn` output. The template already embeds a per-connection **external ID**, which the role's trust policy must require. * **Azure**: an Azure CLI snippet that creates a Reader service principal. Paste back the `clientId` (`appId`) and `clientSecret` (`password`) it prints. * **GCP**: a gcloud snippet that creates a read-only service account and downloads a JSON key. Paste back the service account email and the full contents of the key file. Tick the confirmation box once you have run the template. Odin runs a health check against the new connection and polls until it settles, which usually takes a few seconds. If the check is still running after about 40 seconds, the wizard leaves the account as **Pending** and finishes in the background. The Accounts table picks up the result. Give the role or service principal a moment to propagate before verifying. If verification fails, re-verify from the account's actions menu rather than reconnecting from scratch. ## The accounts table | Column | Description | | ------------- | ------------------------------------------------------------ | | **Provider** | AWS, Azure, or Google Cloud | | **Name** | The display name you gave the connection | | **Account** | The AWS account ID, Azure subscription ID, or GCP project ID | | **Status** | The current connection status | | **Assets** | How many resources have been discovered in this account | | **Last scan** | When the account was last scanned | Filter by provider or status with the two dropdowns above the table. Select rows with the checkboxes to re-verify or delete several accounts at once. ### Account statuses | Status | Meaning | | ---------------- | ----------------------------------------------------------- | | **Connected** | The last health check succeeded and scans are running | | **Pending** | The first health check hasn't finished yet | | **Degraded** | The connection works but the health check raised a warning | | **Disconnected** | Heimdall can no longer reach the account | | **Error** | The health check failed. The reason is shown on the account | ## Account actions The actions menu on each row offers: * **Scan now**: queue a discovery scan, which refreshes the asset inventory * **Run CSPM scan**: queue a security scan, which evaluates the inventory and produces findings * **Re-verify**: re-run the health check, for example after fixing permissions * **Delete**: remove the connection ## Account details Click a row to open the detail panel. **Overview** shows the asset count, the last scan, the last health check, and when the account was connected. **Scan settings** manages the account's schedules, and **Scan history** lists recent runs, and clicking one opens its [scan run](#scan-runs) page. Below that, a provider section lists the identifiers Odin holds for the connection, including the AWS external ID and role ARN. ### Scan schedules An account can carry several schedules. Each one sets: * **Scan type**: **Discovery** to refresh the inventory, or **CSPM** to evaluate it * **Frequency**: hourly, every 4 hours, every 12 hours, daily, or weekly * **Profile**: the Prowler profile to run, `default` unless you have been given another * **Minimum severity**: the lowest severity Heimdall reports from the scan Add a schedule with **Add schedule**. Odin rejects a duplicate of one that already exists on the account. Each schedule row has a switch to pause it without deleting it. ## Scan runs A scan run page reports its status (queued, running, completed, failed, or cancelled), when it started and completed, how long it took, and how many resources it discovered, updated, and removed. A failed run also shows its error log. # Cloud assets Source: https://docs.borghq.io/platform/cloud/assets Browse the inventory of resources Heimdall discovers in your cloud accounts Cloud is currently unavailable in Odin. The Cloud Assets inventory is parked. Contact Borg if you need a cloud inventory. **Cloud → Assets** is the inventory of every resource discovery scans have found across your connected AWS, Azure, and GCP accounts. ## Provider cards Three cards at the top of the page show each provider's asset and account counts. Click one to filter the table to that provider, and click it again to clear the filter. ## Filtering Above the table you can narrow the inventory by: * **Search**: matches an asset name, ARN, or ID * **Provider**: AWS, Azure, or Google Cloud * **Category**: Compute, Storage, Networking, IAM, Database, Kubernetes, Serverless, DNS, or CDN * **Type**: the specific resource type, such as an S3 bucket or an EC2 instance * **Region**: any region assets have been found in * **Account**: one of your connected accounts * **Tag**: click a tag in the table to filter by it ## The assets table | Column | Description | | ------------- | ------------------------------------------------------- | | **Provider** | The cloud the resource lives in | | **Type** | The resource type | | **Name** | The resource name | | **Region** | Where the resource is deployed | | **Account** | The connected account it belongs to | | **Tags** | Provider tags, each one clickable as a filter | | **Last seen** | When a scan last saw the resource | | **Public** | Marked when the resource is reachable from the internet | Sort by type, name, region, or last seen by clicking the column heading. ## Exporting The **Export** menu downloads the current view, filters included, as CSV, Markdown, or JSON. Pressing E anywhere outside a text field exports to CSV straight away. ## Asset details Click a row to open the asset. The header carries its resource type, category, and region, plus a **Publicly exposed** badge where it applies, a **Stale** badge when the latest scan didn't see it, and a badge for each data class recorded against it. Below that: * **Overview**: the ARN, the provider's native ID, when the asset was first discovered, and when it was last seen * **Tags**: every provider tag on the resource * **Metadata**: the configuration Heimdall recorded, which is what [custom rules](/platform/cloud/custom-rules) match against * **Relationships**: the asset's parent, its children, and other related assets, each one a link * **Findings**: cloud findings raised against this asset, with their severity and status # Custom cloud rules Source: https://docs.borghq.io/platform/cloud/custom-rules Write your own CSPM checks and run them against your cloud assets Cloud is currently unavailable in Odin. Custom cloud rules are parked. Contact Borg if you need a rule added. **Cloud → Settings → Custom Rules** is where you define your own cloud security checks. An enabled rule runs during every CSPM scan, and each asset it matches becomes a finding. Custom rules sit alongside the standard checks Heimdall already runs. Use them for the policies specific to your organisation, such as a tagging standard or an encryption requirement. ## The rules table | Column | Description | | -------------- | --------------------------------------------- | | **Name** | What the rule checks | | **Severity** | Critical, High, Medium, or Low | | **Category** | Your own grouping label, such as `encryption` | | **Conditions** | How many conditions the rule combines | | **Scope** | Which assets the rule applies to | | **Enabled** | A switch to turn the rule on or off | The actions menu on each row lets you edit, test, or delete a rule. Turning a rule off keeps it for later without running it. ## Starting from a template **Browse templates** opens a gallery of ready-made checks for common misconfigurations, including unencrypted S3 buckets, security groups open to `0.0.0.0/0` on port 22, resources missing an `Environment` tag, IAM users with console access but no MFA, and publicly accessible databases. **Use template** creates a normal custom rule from the definition, which you can then edit like any other. ## Writing a rule **New rule** opens the rule builder. ### Details Name the rule after what it enforces. `All S3 buckets must have encryption enabled` reads better in a finding than `S3 rule 1`. Add a description, a severity, and a category of your choosing. ### Conditions Each condition tests one field on an asset. The field is a dot-path into the asset record, so `metadata.encryption.enabled` reads the encryption block Heimdall captured and `tags.Environment` reads a tag. You can see the fields available on any asset under **Metadata** on its [detail page](/platform/cloud/assets#asset-details). The operators are **equals**, **not equals**, **contains**, **greater than**, **less than**, **exists**, and **does not exist**. The last two take no value. Conditions are combined with AND. Every condition has to hold for an asset to match. To express an OR, write one rule per branch. ### Scope Scope limits which assets the rule is evaluated against. Leave a field empty to place no limit on it: * **Providers**: AWS, Azure, or Google Cloud * **Resource types**: specific types such as S3 buckets or EC2 instances * **Regions**: a list of regions * **Accounts**: specific connected accounts * **Tag filters**: key and value pairs, using the same equals, not equals, exists, and does not exist operators ### Remediation **Guidance** explains how to fix a violation and **Reference URL** links to supporting documentation. Both appear on the findings the rule raises, so whoever picks one up knows what to do. ## Testing a rule **Test** on any rule dry-runs it against your current assets. The result reports how many assets matched out of how many were in scope, and previews the first of them with their name, type, provider, and region. A test writes nothing and creates no findings, so it is the quickest way to check that a condition path is right before you switch a rule on. # Cloud overview Source: https://docs.borghq.io/platform/cloud/overview Track the security posture of your connected AWS, Azure, and GCP accounts Odin's Cloud section scans your AWS, Azure, and GCP estate with **Heimdall**, Borg's cloud scanner. It builds an inventory of your cloud resources, checks them against security rules, and tracks how your posture changes over time. Cloud is currently unavailable in Odin. The Cloud pages and APIs are parked, not removed. Contact Borg if you need a cloud scan or account connected. The section has five pages: * **Overview**: posture score, provider breakdown, account health, and the highest-severity findings * **[Accounts](/platform/cloud/accounts)**: connect cloud accounts and schedule their scans * **[Assets](/platform/cloud/assets)**: the inventory of discovered resources * **[Reviews](/platform/cloud/reviews)**: AI-written assessments of your cloud posture * **[Settings](/platform/cloud/custom-rules)**: your own cloud security rules ## Getting started Open **Cloud → Accounts** and follow the connect wizard for AWS, Azure, or GCP. See [Connecting cloud accounts](/platform/cloud/accounts). The overview shows a **first scan running** state until discovery completes. Resources then appear under **Cloud → Assets**. Discovery builds the inventory; CSPM scans evaluate it against security rules. Add a CSPM schedule on the account, or run one on demand from the account's actions menu. Until you connect your first account the overview shows a prompt to do so instead of the posture cards. ## Posture score The headline card scores your estate out of 100, based on account health and how many assets are publicly exposed. Beside it are your total asset count and your publicly exposed asset count, which turns red as soon as it is above zero. Odin takes a snapshot of the score once a day. The badge next to the score is the change since the previous snapshot, and the sparkline covers the last 30 days. ## Provider breakdown One card per provider (AWS, Azure, and Google Cloud) with its account count, asset count, finding count, and critical finding count. A provider you haven't connected is drawn with a dashed border. ## Accounts status A count of your accounts by connection status, so a degraded or errored connection is visible without opening the Accounts page. See [account statuses](/platform/cloud/accounts#account-statuses) for what each one means. ## Risk trend A 30-day chart of your posture score. It needs at least two daily snapshots before it renders, so expect it to be empty on your first day. ## Critical findings The highest-severity cloud findings across all your accounts, with a count of critical findings against the total. This stays empty until CSPM scanning runs, because discovery alone doesn't produce findings. Cloud findings are separate from the [Findings](/platform/findings) page, which covers pentest, threat model, and imported findings. Cloud findings are shown here and on each asset's detail page. ## Billing Cloud scanning consumes credits under the **Cloud Review** product. You can see the usage on the **Usage** chart and each individual deduction on the **Ledger** tab of the [Billing](/platform/billing) page. # Cloud reviews Source: https://docs.borghq.io/platform/cloud/reviews Ask an AI analyst to assess the posture, attack paths and priorities across your connected cloud accounts A cloud review is a written assessment of your cloud estate. An AI analyst reads the posture data Heimdall has already collected (your accounts, assets, cloud findings and the relationships between them) and writes up what is wrong across your accounts and what to fix first. Reviews live under **Cloud → Reviews**. They read the data that [scanning](/platform/cloud/accounts) has produced, so connect at least one account and let a CSPM scan run before requesting one. Cloud is enabled per organisation. If you don't see a **Cloud** group in the sidebar, contact your account manager to have it turned on. ## Requesting a review The page lists every review your organisation has requested, newest first. The button is disabled, with the reason in its tooltip, when you have no cloud accounts connected, when a review is already in progress, or when your role is read-only. Every account is selected by default. Untick the ones you want left out, or use **All accounts** to clear and restore the whole list. Leaving everything ticked sends no explicit list at all, which the analyst reads as every account in the organisation. Odin queues the review and opens its detail page, where you can watch it run. You can have one review in progress at a time. Requesting a second while one is queued or running is rejected, which is also why the **Request review** button is disabled until the current one finishes. ## While a review runs A queued or running review shows a three-step progress panel (Queued, Analysing, Report ready) with a live timer, both on the Reviews page and on the review's own page. Odin polls every few seconds, so you do not need to reload the page. Most reviews finish in a few minutes. If nothing picks up a queued review within 30 minutes, Odin marks it failed and releases the slot so you can request another. ## Reading the report A completed review opens with four figures: * **Completed**: when the analysis finished * **30-day posture**: the change in your posture score over the last 30 days, or *No trend data* when there aren't enough daily snapshots yet * **Findings considered**: how many cloud findings went into the analysis * **Attack paths**: how many attack paths the analyst examined in your cloud graph Below them the report is split into five sections. A sidebar tracks where you are as you scroll. | Section | What it covers | | -------------------- | ------------------------------------------------------------------- | | Executive summary | The state of the estate in plain terms, for sharing upwards | | Risk overview | Where the risk is concentrated, by account and by resource type | | Attack paths | Chains of misconfigurations an attacker could follow end to end | | Findings by severity | The findings behind the assessment, grouped by how serious they are | | Recommendations | What to fix, in the order worth doing it | The model that wrote the report is named next to the request date. ## Review cards Each card on the Reviews page carries the request date, the current status, a badge per provider with how many of its accounts were in scope, and the same posture, findings and attack-path figures as the report. A failed review shows the reason it failed instead. ## When a review fails A failed review states why on both its card and its detail page. Odin does not retry it, so request a new review once you have dealt with the cause. Usually that is a review nothing picked up in time, or an account whose connection had broken by the time the review ran. Check the account's status on [Accounts](/platform/cloud/accounts#account-statuses). ## Roles and billing Owners, admins and members can request a review. Read-only members can open and read every review but cannot start one, because each review spends credits. Reviews are billed under the **Cloud Review** product and appear on the **Ledger** tab of the [Billing](/platform/billing) page. A review that fails is not charged. # Command Palette & Shortcuts Source: https://docs.borghq.io/platform/command-palette Move around Odin without taking your hands off the keyboard Odin has a command palette for fast navigation and entity search, plus a set of keyboard shortcuts modelled on Vim and Linear. Once you've internalised them, you can drive most of the product without touching the mouse. ## Command palette Open the command palette with ⌘+K (macOS) or Ctrl+K (Windows/Linux). From the palette you can: * **Navigate to a page**: Home, Alert Centre, Findings, HackerOne, Assets, PR Reviews, pentest settings, Integrations, Reports, Team, API Keys, and Edit Profile * **Search findings** by title: start typing (minimum 2 characters) to see up to five matches, most severe first * **Search assets** by name: same minimum length, up to five matches, most recently seen first * **Jump to recently visited pages**, listed before you start typing Picking an asset opens that asset on the Assets page. Picking a finding opens the Findings list filtered to that title rather than the finding itself, so you'll land on the list with the search box already filled in. The palette only ever offers pages your organisation has access to, so your list may be shorter than the one above. While your organisation is on a trial, it also carries **Restart setup wizard** and **Continue tour**. ## Keyboard shortcuts dialog Press ? anywhere in the app to open the keyboard shortcuts reference. It lists the global, navigation and list shortcuts, and hides any destination your organisation can't reach. The page-specific shortcuts further down this page aren't in it. ## While you're typing Every shortcut on this page except ⌘+K is ignored while your cursor sits in a text field or a rich-text editor, so typing a `j` into a search box won't move the list. Click away from the field, or press Escape, to get the shortcuts back. ## Global | Shortcut | Action | | -------------------------------------------------------- | --------------------------------------------- | | ⌘+K / Ctrl+K | Open command palette | | ? | Show the shortcuts dialog | | f | Open the [feedback panel](/platform/feedback) | ## Navigation Press the first key, then the second key within about half a second, to jump to a page. If you pause too long the sequence resets and you can start again. | Shortcut | Destination | | ------------------------- | ------------- | | g h | Home | | g a | Alert Centre | | g f | Findings | | g b | HackerOne | | g t | Threat Models | | g s | Assets | | g i | Integrations | | g r | Reports | A sequence pointing at a page your organisation can't reach does nothing, and that row is hidden from the shortcuts dialog. ## List navigation These work on the Findings, Assets, Integrations, Reports and Team pages. | Shortcut | Action | | -------------------------------------------------------- | --------------------------------------- | | j / ↓ | Move the highlight down | | k / ↑ | Move the highlight up | | g | Jump to first item | | Shift+G | Jump to last item | | x | Toggle selection on the highlighted row | | Enter | Open the highlighted item | | Escape | Clear the highlight and the selection | | ⌘+A / Ctrl+A | Select all loaded items | The highlight wraps: j on the last row returns to the first. ⌘+A covers the rows currently loaded into the list, not everything behind the filter, so pages that load more as you scroll will select only what you've scrolled through. What Enter opens depends on the page: * **Findings**: the finding's detail panel * **Assets**: the asset's detail panel * **Integrations**: the provider's setup dialog * **Reports**: downloads the report's PDF, if it has one * **Team**: the edit dialog for that member, if you're allowed to manage the team The selection keys, x and ⌘+A, only do something where the page has a selection to act on. Findings marks the selected rows and opens the bulk action bar for a status update or an export, which needs the Member role or higher. Assets marks the selected rows but has no bulk action behind them. On Integrations, Reports and Team the two keys do nothing you can see. While a dialog is open the list keys pause, so Escape closes the dialog rather than clearing your place in the list. That covers the finding detail panel, the Assets add and import dialogs, the Reports email dialog, and the Team invite and edit dialogs. ## Page-specific shortcuts Two pages add their own shortcut: * **Suppression Rules**: press c to open the new rule dialog * **Home dashboard**: press r to refresh all dashboard data without reloading the page # Continuous Asset Discovery Source: https://docs.borghq.io/platform/continuous-asset-discovery Automated discovery and enumeration of your external attack surface Continuous Asset Discovery (CAD) automatically finds and monitors your external attack surface around the clock. Turn it on for a root domain or IP, and Odin discovers subdomains, open ports, running services, and linked infrastructure — keeping your asset inventory current as your environment changes. As your organisation grows, new subdomains, services, and infrastructure appear regularly. CAD picks these up automatically, so your security team always has a complete picture without coordinating across teams or manually importing every asset. ## Scan schedule CAD runs three scan tiers on a recurring basis: | Tier | Frequency | What it does | | -------------- | ------------- | --------------------------------------------------------------------------------- | | **Hourly** | Every hour | Light DNS enumeration to discover new domains and subdomains | | **Tri-hourly** | Every 3 hours | Advanced enumeration techniques for deeper domain and subdomain discovery | | **Daily** | Once per day | Full port scan across all 65,535 ports, IP-address linking, and service labelling | All scanning is non-intrusive. Newly discovered assets are automatically added to your [Assets](/platform/assets) inventory. ## Recon types DNS enumeration, HTTP probing, and TLS inspection on domains and subdomains. Identifies web servers, WAFs, certificates, and technologies in use. Scans the full port range (65,535 ports) on IP addresses. Identifies open ports, running services, and version information. For certain services, Odin uses targeted probing to extract detailed configuration. ## Recon results Recon data is available on each asset's detail page. Click any asset on the [Assets](/platform/assets) page to view its results. For domains and subdomains, Domain Recon surfaces: * **Web server**: the detected web server (e.g. Cloudflare, Nginx) * **TLS**: protocol version and cipher details (e.g. TLS 1.3) * **Certificate**: certificate subject and issuer * **WAF**: detected web application firewall * **IP**: resolved IP address * **HTTP status**: response code and latency * **DNS records**: A, AAAA, CNAME, and other resolved records Asset detail panel showing Domain Recon results for a subdomain, including web server, TLS, certificate, WAF, IP, HTTP status, and DNS records For IPs, Network Recon shows open ports, detected services, and version information where available. ## Turning monitoring on or off Continuous monitoring is controlled for your whole organisation from the **Continuous monitoring** card under **Billing → Credits**. Admins can switch it on or off at any time: * **On** — CAD runs on your schedule and is billed at 4 credits per monitored asset per month, prorated daily. * **Off** — all scanning stops and no CAD credits are charged. Your discovered assets are **preserved** in your [Assets](/platform/assets) inventory; turning monitoring back on resumes it. When monitoring is off, an asset's detail panel shows CAD as **Off** rather than an editable toggle, since the organisation-level switch takes precedence. CAD is billed from your plan's credits. Visit **Billing** in the sidebar to review usage, or contact [mail@borghq.io](mailto:mail@borghq.io) to discuss your plan. # Feedback Source: https://docs.borghq.io/platform/feedback Report bugs, request features, and track where your feedback stands Odin has a built-in feedback panel so you can flag a bug, ask for a feature, or share a thought without leaving the app. Everything you send lands directly in our queue, and you can follow each item through to resolution from the same panel. ## Opening the panel There are three ways to open it from anywhere in the dashboard: * **Sidebar**: click **Feedback** at the bottom of the navigation * **Account menu**: open the user menu in the top bar and choose **Give feedback** * **Keyboard**: press F (ignored while you're typing in a field) The panel opens in the bottom-right corner. Press Escape or click outside it to close. ## Sending feedback Pick a category, give it a title, and send. Only the title is required. | Category | Use it for | | ----------- | ------------------------------------------------- | | **Bug** | Something isn't working as expected | | **Feature** | A new capability or improvement you'd like to see | | **General** | A thought, question, or impression | The **title** is a short summary (up to 120 characters). The **description** is optional and supports Markdown, so use it for steps to reproduce, context, or detail. Drop a screenshot onto the form or click the upload area to browse. You can attach up to 4 files (10MB each) — images, PDFs, or log files. Attachments land alongside your feedback so the team sees exactly what you saw. Toggle **Mark as urgent** to push the item higher in our queue. Keep it for things that are blocking you. Click **Send feedback**. You'll get a confirmation with a reference like `FB-123` so you can refer back to it. ## Tracking your feedback Switch to the **My feedback** tab to see everything you've submitted, newest first. Each row shows its category, reference, and current status. Open any item to see its full history. Every item moves through three stages: | Status | Meaning | | --------------- | ---------------------------------- | | **Received** | We've got it and it's in the queue | | **In Progress** | We're actively working on it | | **Resolved** | It's been addressed | The detail view shows a status timeline alongside an **Updates** thread. When someone on our team replies or the status changes, the update appears there, so the panel stays the single place to check where things stand. Any files you attached are listed under **Attachments** in the same view. Click one to open it in a new tab. The links are short-lived and only you can use them, so reopen the item if a link has expired. Status updates and team replies sync automatically, so you don't need to refresh the panel or chase anyone for a response. # Findings Source: https://docs.borghq.io/platform/findings Track, triage, and remediate security issues across your organisation Findings are security issues identified across your assets and pentest runs. Everything Mjolnir discovers, plus issues from Borg's continuous monitoring, manual triage by our team, or imports from your existing tooling, lands here. If more findings exist on the organisation than your current plan includes, Findings uses the same note as Home — how many are on a paid plan — rather than a separate unverified-candidate count. Starting a Micro Pentest from Odin is currently unavailable. ## Engine findings Mjolnir v2 reports some issues as **engine findings** — the source report from the run, shown alongside client tickets. Engine findings are read-only until you promote them. **Promote to ticket** creates a normal Odin finding with an organisation identifier (for example `BORG-12`) so you can assign it, change status, discuss it, and push it to Linear, Jira, GitHub, or GitLab. The engine report stays as the source; workflow lives on the ticket. After you promote, lists show the ticket instead of the engine row. Opening the previous engine id still resolves to that ticket. Unpromoted engine findings cannot have their status or assignee changed, and cannot be pushed to an issue tracker, until they are promoted. The ticket carries the report write-up (summary, description, impact, details, remediation, and affected assets). Extra engine planes such as live/code evidence stay on the engine report, not on the ticket. Odin findings dashboard showing a list of security findings with severity indicators ## Severity levels Each finding gets a severity based on exploitability and impact. Severity is set by Borg's analyst team or by Mjolnir, and is anchored to a CVSS base score: | Severity | CVSS range | Description | | ------------ | ---------- | ---------------------------------------------------------------------- | | **Critical** | 9.0 – 10.0 | Immediate exploitation risk. Requires urgent remediation. | | **High** | 7.0 – 8.9 | Significant risk with a realistic exploitation path. Address promptly. | | **Medium** | 4.0 – 6.9 | Real issue but harder to exploit or lower impact. Plan remediation. | | **Low** | 0.1 – 3.9 | Minor issue or defence-in-depth improvement. Fix when practical. | Lists, board cards, and the severity filter show this as a compact mark: a red warning triangle for **Critical**, and the three-bar signal for High through Info. Critical findings also carry a faint red tint and outline in the list and on the board card, so they stand out without relying on the mark alone. Click a severity in the stats bar at the top of the Findings page to filter to it. ## Confirmation type Mjolnir findings carry a confirmation type alongside their severity. Severity is how serious the issue is. Confirmation type is how Mjolnir established it was real, and how much evidence sits behind it. | Confirmation | What it means | | ------------- | ------------------------------------------------------------------------------------ | | **Exploited** | Mjolnir ran the attack end to end and proved it works. This is the strongest signal. | | **Partial** | Mjolnir found evidence the issue is real but stopped short of a working exploit. | | **Static** | Mjolnir confirmed the issue by reading the source code, without running an attack. | The confirmation type is available in the finding detail view and filters. It is not shown on list rows, keeping the queue focused on priority and ownership. Findings our analyst team raises by hand don't carry a confirmation type, so it only applies to Mjolnir findings. Filter by **Confirmation** in the filters bar to focus on one level, such as only the issues Mjolnir has fully exploited. ## Finding status Each finding moves through a status lifecycle that captures the back-and-forth between your team and Borg as a fix is applied and verified: | Status | What it means | Set by | | -------------------- | ------------------------------------------------------------------------------------ | --------- | | **Reported** | The finding has been published to your team and is awaiting triage | Borg | | **Mitigating** | Remediation is in progress on your side | Your team | | **Needs Revision** | Borg retested and the fix is insufficient (or introduces a new issue) | Borg | | **Open for Retest** | You've applied a fix and want Borg to verify it | Your team | | **Fixed & Retested** | Borg has verified the remediation is effective | Borg | | **Acknowledged** | You've seen the finding and accepted the risk for now; not actively being remediated | Your team | List groups, board columns, and status filters use a square workflow mark: empty at Reported, a single line across the top while Mitigating, halfway around (top and right) at Needs Revision, three sides at Open for Retest, a hollow square at Acknowledged, and a completed square with a tick at Fixed & Retested. The colours match Home: amber for Mitigating and orange for Needs Revision. ### Changing the status **Member**, **Admin**, and **Owner** roles can move a finding between client-controlled states from the finding detail view, by right-clicking a list row or board card, or by dragging a card between columns on the board: * **Reported** → Mark as Mitigating, or Acknowledge * **Acknowledged** → Resume Mitigation * **Mitigating** → Mark as Open for Retest, or Acknowledge * **Open for Retest** → Reopen as Mitigating, or Acknowledge * **Needs Revision** → Resume Mitigation, or Mark as Ready for Retest You can optionally attach a comment when changing status. Borg sees the comment alongside the status change in the activity timeline. Right-click a list row or board card for the rest of the finding's actions without opening it: **Open**, **Open in new tab**, then hover **Copy** for the identifier, link, branch name, or agent prompt, and hover **Status** to move it. You can also assign it, create a tracker issue, or open its retest. Right-click a row that's already in a multi-selection to act on every selected finding at once — hover **Copy** or **Status** for the same actions across the selection. After every status change, a toast appears with an **Undo** action. Use it if you change a finding's status by mistake. ## Assigning findings Assign a finding to a teammate so it's clear who owns getting it fixed — the same way you'd assign an issue in Linear or Jira. * On the **Findings** table, each row has an assignee avatar in its own column, between the title and the created date. Click the avatar — or the dashed placeholder on an unassigned finding — to pick an assignee inline, without opening the finding. You can also assign from the right-click menu on a table row or board card. * Inside a finding, use the **assignee** control in the header to assign, reassign, or clear. Findings can be assigned to any **Owner**, **Admin**, or **Member** — the roles that can act on findings. **Read only** members can't be assigned. Assigning requires the Member role or higher. When you assign someone, they receive an in-app notification and an email that the finding is now theirs. Changing or clearing the assignee updates everywhere instantly, and the change is recorded in the finding's [activity timeline](#discussion-and-activity). If the finding is linked to an issue in a connected tracker, the assignment syncs there too, and a reassignment in the tracker flows back to Odin. See [assignee sync](/platform/integrations/overview#assignee-sync). Hover an assignee avatar in the list to see who a finding is assigned to without opening it. ## Following findings Follow a finding to get notified about its updates, independent of whether you're assigned to it. * Inside a finding, a **Follow** / **Following** button (bell icon) sits next to the assignee control, alongside a count of how many people are subscribed. * Following a finding means you get notified about updates to it — status changes, comments, and other activity — through the [Alert Centre](/platform/notifications). You don't need to follow a finding manually to end up subscribed to it: * When a finding is **reported**, your organisation's [default finding subscribers](/platform/organisation-settings#default-finding-subscribers) are subscribed automatically — every non-**Read only** member, unless your organisation has customised the list. If the delivery includes a **Critical** finding, those default subscribers are also emailed. * Interacting with a finding subscribes you too: changing its status, commenting, being `@mentioned`, or being assigned. * **Assignees** always follow the findings assigned to them and can't unfollow while the assignment stands — unassign first if you want to stop following. Unfollowing is remembered: Odin won't automatically re-subscribe you to that finding again, though you can always follow it again manually. **Read only** members can follow findings too, even though they can't be assigned. ## Finding identifiers and PR linking Every finding has a unique, human-readable identifier made from your [organisation's finding prefix](/platform/organisation-settings) and a sequence number — for example `BORG-12`. Preview findings from the free Micro Pentest use the same sequence. The identifier is shown in the finding header and on every list view, and it's how findings get connected to your engineering work. When the [GitHub integration](/platform/integrations/github) is connected, referencing that identifier from a pull request — in the branch name, title, or body — links the PR to the finding automatically. You can also link one by hand. Linked PRs show as chips in the finding header and track their open, merged, or closed state live. Linking a fix is also the trigger for verifying it: once a linked PR merges, Odin can review the change and confirm whether the finding is resolved, moving it to **Fixed & Retested** or **Needs Revision** without a manual retest step. How to link a pull request to a finding — three ways — and how Odin verifies the fix when it merges ## What's inside a finding Every finding contains: * **Title and severity**: a one-line summary plus severity label and CVSS score * **Confirmation type**: for Mjolnir findings, how strongly the issue was confirmed — exploited, partial, or static * **Type**: when set, the header shows the CWE identifier; hover it for the class name * **Repository**: when the finding belongs to a repository, a chip in the header opens it in a new tab * **Affected assets**: the domains, endpoints, or resources where the issue applies. Assets Odin already tracks link through to the [attack surface](/platform/assets), where you can see the rest of what's known about that host * **Description**: what the vulnerability is * **Impact**: the business consequence if it were exploited * **Details**: technical details, including how the issue was identified * **Remediation**: step-by-step fix guidance * **Proof of Concept**: for Mjolnir findings, the request/response evidence captured during exploitation * **Code Reference**: for Mjolnir findings with a code pointer, the exact file and line in your repository * **Status history**: every status change, who made it, and any attached comment The repository chip takes the repository the finding itself records. Where the finding doesn't record one, a linked pull request supplies it instead, preferring an open PR over a merged or closed one. The link keeps the host that pull request came from, so a repository on a self-hosted GitHub Enterprise server resolves against your server rather than github.com. ### Revisions Findings are immutable. Whenever Borg's analyst team or Mjolnir updates the content of a finding (after retesting, for example), a new **revision** is created. From the second revision onward the header shows `v2`, `v3`, and so on. You always see the current revision, but the full history is preserved on Borg's side for audit. ## Views The Findings page has three view modes you can switch between in the toolbar: * **Table**: the default workspace view, with filters, sort, and a detail panel. Columns are Severity, ID, Title, Assignee, and Created. Rows are grouped by the remediation workflow unless you change that under Display. Right-click a finding row for quick status changes, assignee, copy, follow, and linked-resource actions; right-click a group header to collapse it, act on the group, or hide it. Acknowledged and Fixed & Retested stay in the grouped table with their counts even while those findings are hidden — press **Expand** on the group header to reveal them. * **Board**: findings grouped into status columns, each with that status's workflow mark. Drag a card onto another column to update its status. The card stays in the destination column after the update. Columns you cannot move a finding into (Reported, Needs Revision, and Fixed & Retested) do not accept the drop — those states are set by Borg. Acknowledged and Fixed & Retested columns still show their counts when hidden; press **Show** or **Hide** next to the column title to reveal or collapse the cards. * **Heatmap**: a severity-by-status matrix showing how findings are distributed across your portfolio ## Filtering and search Filters at the top of the page narrow your view. Open the filter button to browse the grouped menu: * **Saved views**: quickly switch to My queue, Needs attention, Waiting on Borg, or Accepted risk. You can also save the current filter set as a named view. * **Severity**: select one or more of Critical, High, Medium, Low, or Info. The menu keeps the priority signal visible beside each count. * **Status**: filter by Reported, Mitigating, Needs Revision, Open for Retest, Fixed & Retested, or Acknowledged. The counts stay visible even when Fixed & Retested or Acknowledged are collapsed by default. * **Hidden groups**: groups hidden from the Table view are remembered per organisation in this browser. Open the filters menu and use **Hidden groups** to restore one group or all hidden groups. * **Assignee**: filter to one or more teammates, or to unassigned findings. * **More filters**: access confirmation type, pentest, asset, repository, and ordering filters without crowding the primary menu. * **Search**: free-text search across titles and identifiers The URL updates as you filter, so any view can be bookmarked. Exports use the same active filters. Your custom saved views are stored locally in your browser. Built-in views are available in every organisation, while a custom view stays scoped to this browser. ## Bulk operations Select multiple findings with the row checkboxes, or navigate with `j`/`k` and toggle selection with `x`. You can also right-click a finding row and use its quick status or assignee actions. With a selection active, a bulk action bar appears above the findings list: * **Update status** — move all selected findings to Mitigating or Open for Retest * **Copy for Agent** — copy a single prompt covering every selected finding, formatted to hand straight to a coding agent. A toast confirms how many findings were copied. * **Export** — download the selected findings as CSV, CSV (summary), Markdown, or JSON The bulk export and copy controls pull full finding detail for the selection, so the files match the page-level export rather than the columns shown on screen. Bulk operations require the **Member** role or higher. ## Discussion and activity Every finding has a right-hand rail with two tabs. Collapse it with the chevron on the rail so the write-up can use the full width; expand it again from the strip on the right. Odin remembers that choice. A link that opens the Discussion or Activity tab expands the rail if it was collapsed. * **Discussion**: a threaded conversation with Borg's analyst team. Use `@` to mention a teammate, attach files, and resolve threads when a question is settled. You can edit or delete your own messages from the message's menu; an edited message is labelled accordingly. The thread updates live, so replies from the Borg team appear as they are posted without reloading the page. New replies can trigger email notifications based on your [discussion preferences](/platform/profile). * **Activity**: a chronological feed of every status change, revision, and integration sync for the finding ### Mentioning teammates, findings and projects Typing `@` in a discussion opens a search grouped into **People**, **Findings**, and **Projects** (pentests). Start typing a name, finding title or identifier, or project name to filter each group. * **People** mentions notify the teammate, as they always have. * **Findings** and **Projects** mentions are links only and notify no one. A mentioned finding shows as a chip with its current status and severity, and a mentioned project links through to its findings. A finding chip reads its status live each time the thread loads, so it shows the finding's current status rather than its status when the message was posted. If a finding is later deleted, or you lose access to it, its chip turns muted and stops linking through. ## Exporting findings Click **Export** in the page header to download your current filtered view. The export respects every active filter, so narrow down by severity, status, and the rest before exporting. | Format | Description | | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **CSV** | Spreadsheet-friendly format with columns for identifier, title, severity, CVSS, status, type, affected assets, summary, description, business impact, details, remediation, and timestamps | | **CSV (summary)** | A compact spreadsheet with just title, severity, CVSS, status, and discovered date — for a quick overview rather than full detail | | **Markdown** | Human-readable format with each finding as a section, including metadata tables and full descriptions | | **JSON** | Machine-readable format with the same data, useful for scripting or importing into other tools. Findings with agent evidence also carry structured proof-of-concept and code-reference fields | Findings you've [pushed to an issue tracker](#pushing-findings-to-your-issue-tracker) carry their linked issues into the export: * **CSV** and **CSV (summary)** gain two columns after **Status**: **Linked Issue References**, which lists each issue by tracker and identifier (for example `GitHub #42` or `Linear ODIN-1272`), and **Linked Issue URLs**. Where a finding has more than one linked issue, they're separated by semicolons. These columns appear only when at least one finding in the export has a linked issue. * **Markdown** adds a **Linked Issues** line to each finding that has one, with every issue linking back to the tracker. * **JSON** includes a `linkedIssueReferences` array on each finding, recording the provider, identifier, URL, and provider-specific detail such as the repository or project. ### From a single finding The finding detail header shows the identifier and the reported date on the same row as the compact actions. The title sits on its own row and wraps across the full header width. The **Copy** control is a menu (chevron) covering: * **Copy link** — copy a shareable URL that opens this finding directly * **Copy Markdown** — copy the finding as Markdown * **Copy for Agent** — copy a prompt describing the finding to hand to a coding agent * **Copy branch name** — copy a `fix/…` branch name derived from the finding * **Download Markdown** — save the finding as a Markdown file ## Pushing findings to your issue tracker If you've connected Linear, Jira, GitHub, or GitLab, you can push any finding directly to your issue tracker with one click. The finding title, severity, description, impact, and remediation are all included, plus a deep link back to the finding in Odin. You can also enable [auto-ticketing](/platform/integrations/linear#auto-ticketing) so that issues are created automatically as new findings are reported. [Shortcut](/platform/integrations/shortcut) is also supported, but only through auto-ticketing or a bulk sync. There's no one-click push for a single finding. Set up your integration at **Management > Integrations**. Connect Linear, Jira, GitHub, or GitLab Some actions require re-authentication # Home Dashboard Source: https://docs.borghq.io/platform/home-dashboard Your security posture at a glance The Home dashboard is the first thing you see after signing in. The page title states the one thing that needs attention — for example how many critical findings are still open — so you do not have to scan the rest of the page to know where you stand. Press g h from anywhere to get back to it. ## Glance numbers Four numbers sit under the title. Each one is a link: * **Critical** — findings that are still open at critical severity * **High** — findings at high severity * **For retest** — findings waiting on a retest * **Assets** — hosts in your attack surface During the free Micro Pentest trial the three finding counts match the [Findings](/platform/findings) page — they only include that trial, not other pentests. The refresh icon in the top right reloads every card without reloading the page. Pressing r does the same thing. ## Finish setting up If your name is missing, GitHub is not connected, or billing is not set up yet, a **Finish setting up** card appears under the page title. Each row says why it matters and takes you through: * **Add your name** — so comments and assignments show who you are * **Connect GitHub** — needed for PR reviews (members and admins) * **Turn on billing** — so scans and retests keep running (admins only) A blue progress bar sits at the top of the card. The card tracks how many of those steps are done, and disappears once they are. The same card also appears at the top of **Testing > PR Reviews** for the remaining testing steps. Prepaid pay-as-you-go organisations still see a Home banner when a payment failed, or when billing is already set up but there are no credits left. Plan organisations, and older pay-as-you-go accounts billed after usage, do not get that credits banner. First-time payment setup stays in the **Finish setting up** card rather than a second banner. See [Pay as you go](/platform/pay-as-you-go). The same two setup steps also sit in a **Get started** card at the bottom of the sidebar until they are done: **Connect GitHub** and **Add a payment method**. The card disappears once both are complete. Organisations still on a billed trial see the trial checklist in that slot instead. ## Getting started Home is the same dashboard for every organisation. Turn on PR reviews from **Testing** in the sidebar. Launching a Mjolnir pentest or Micro Pentest from Odin is currently unavailable. The sun or moon control in the top bar switches appearance between Light, Dark, and System. System follows your operating system. ## Prompts and banners When there are **Critical** or **High** findings, an alert banner repeats those same glance counts and links to the [Findings](/platform/findings) page filtered to those severities. The numbers match the Critical and High tiles — they are not a separate “awaiting action” subset. ## Overview cards Open findings sits on the left and takes two thirds of the row. Attack surface and Status stack on the right. The chart stretches to that column so every status stays visible: * **Open findings**: a stacked area chart of open findings over time. Critical sits on top, then High, Medium, and Low. The filled area under each layer is the open count at that date. A finding stays in the stack from the day it is reported until it is acknowledged or fixed and retested. The legend shows the latest counts. During the trial the series includes locked findings so you can see how many there are; a note under the chart says how many need a paid plan. * **Attack surface**: asset counts by type (Domains, Subdomains, IPs). Active, Inactive, and Unverified totals sit at the bottom of the card. Empty types still show `0` so the card stays the same height. * **Status**: counts through the [status lifecycle](/platform/findings#finding-status) — Reported, Mitigating, Needs Revision, Open for Retest, Fixed & Retested, and Acknowledged. Each row uses the same progress mark as Findings, and statuses with no findings still show `0` so the card stays the same height. During the trial these counts include locked findings. **Activity** sits under that grid. Each entry names the finding (or other item) and what changed, plus when it happened. Click an entry to open the related finding, asset, or settings page. What your dashboard shows depends on more than your role. Which pages are switched on for your organisation is a separate setting, so the Critical items banner is hidden when Findings is switched off for you. See [Roles & Permissions](/platform/roles-and-permissions). # Install as an app Source: https://docs.borghq.io/platform/install-as-app Add Odin to your desktop or home screen and open it in its own window Odin can be installed as an app on desktop and mobile. Once installed, it opens in its own window without browser tabs or an address bar, and appears alongside your other applications. Installing does not change how Odin works. You still sign in with the same account, and everything you do syncs with the web version. ## Installing 1. Open [odin.borghq.io](https://odin.borghq.io) and sign in. 2. Click the **install** icon at the right-hand end of the address bar, or open the browser menu and choose **Install Odin**. 3. Confirm the prompt. Odin opens in its own window and is added to your applications. 1. Open [odin.borghq.io](https://odin.borghq.io) and sign in. 2. Choose **File > Add to Dock**. 3. Confirm the name and click **Add**. Odin appears in the Dock and in Launchpad. 1. Open [odin.borghq.io](https://odin.borghq.io) in Safari and sign in. 2. Tap the **Share** button, then **Add to Home Screen**. 3. Tap **Add**. Odin opens full-screen from the home screen icon. 1. Open [odin.borghq.io](https://odin.borghq.io) in Chrome and sign in. 2. Tap the browser menu, then **Install app** or **Add to Home screen**. 3. Confirm the prompt. ## Working offline Odin needs a connection to load findings, assets and other security data. If you open the app while offline, you see an **offline** page with a **Try again** button. Reconnect and tap it to continue where you left off. Your data is not stored on the device for offline use. Only the app's own static files, such as scripts, fonts and icons, are kept locally so pages you have already visited load quickly. ## Updates Updates are automatic. When a new version of Odin is released, the app picks it up on your next visit and reloads once so you are always on the latest build. ## Uninstalling Remove Odin the same way as any other app: from the app's window menu on desktop, or by holding the icon on mobile and choosing **Remove**. Your account and data are unaffected. # Azure DevOps Integration Source: https://docs.borghq.io/platform/integrations/azure-devops Give Mjolnir access to your Azure Repos for pentests and PR reviews Connect Odin to Azure DevOps to give Mjolnir access to your Azure Repos. Mjolnir reads your source code to map routes, authentication flows, and business logic for whitebox pentesting, and — when you enable [PR Reviews](/mjolnir/pr-reviews) — posts review feedback directly on your pull requests. Odin reads your repository contents for pentesting. For PR Reviews it also posts **review comments** and a single **status check** on the pull requests you enable. It never pushes code, creates or merges pull requests, or changes your branches. ## Two ways to connect Odin supports two authentication models for Azure DevOps. Pick the one that fits your security requirements — both end up giving Mjolnir access to the same repositories. | | Delegated (Entra OAuth) | Service principal (federated) | | ----------------------- | ----------------------------------------- | --------------------------------------------------------- | | Identity | Acts on behalf of the person who connects | A dedicated non-human identity you own | | Secret shared with Borg | None (OAuth consent) | None (workload identity federation) | | Setup | One-click consent | You configure a federated credential and repo permissions | | Best for | Quick setup | Least-privilege, ISO 27001 / enterprise reviews | ### Delegated (Entra OAuth) Azure DevOps authenticates through Microsoft Entra ID, the supported successor to the old Azure DevOps OAuth apps. Borg runs a single multi-tenant app, and you consent to it inside your own tenant during the connect flow. Go to **Management > Integrations** in the sidebar. Click **Connect** next to Azure DevOps and choose **Delegated OAuth**. You're sent to Microsoft to sign in and consent to the Odin app for your tenant. Back in Odin, pick the **organisation**, then the **project**, then the **repository** you want Mjolnir to use. You can revoke the connection at any time from your tenant's enterprise-application settings. ### Service principal (workload identity federation) Authenticate with a **service principal you own** in your own Entra tenant, authenticated through **workload identity federation**. Borg never receives or stores a client secret or certificate — instead, our GCP-hosted backend presents a short-lived, Google-signed OIDC token that your service principal's federated credential trusts. This gives you a dedicated non-human identity, least-privilege access, and revocation entirely under your control. Under **Management > Integrations**, click **Connect** next to Azure DevOps and choose **Service principal**. Enter your **Tenant ID**, the **Client (application) ID** of your service principal, and your **Azure DevOps organisation**, then save. Odin shows you three values — an **Issuer**, a **Subject identifier**, and an **Audience**. The Audience is unique to your Odin organisation; copy it with the button rather than typing Microsoft's default. In your Entra tenant, add a **federated credential** to your service principal (app registration) using exactly those values. This is what lets your service principal trust Odin's identity without any shared secret. Add the service principal as a member of your Azure DevOps organisation and grant it, on the nominated repository only: * **Code (Read)** — clone the repository and read pull requests * **Contribute to Pull Requests** — post PR review comments and the status check No code-push or branch-write, no work-item access, and no organisation- or project-administration rights are required. Back in Odin, click **Test connection**. Odin mints a token, counts the repositories the service principal can see in your nominated organisation, and reports the total. A non-zero count confirms both the federation and the Azure DevOps permissions are correct. Only needed if you want [PR Reviews](/mjolnir/pr-reviews) — skip it for pentest-only use. After you save, Odin also shows a **webhook URL** and an **`X-Mjolnir-Token`** header value. Because a least-privilege service principal cannot register webhooks itself, an Azure DevOps organisation admin adds these by hand: in the project's **Service Hooks**, create a **Web Hooks** subscription for both **Pull request created** and **Pull request updated**, each posting to the webhook URL with the `X-Mjolnir-Token` header shown. (The delegated OAuth model registers these automatically.) You still enable PR reviews per repository from the [Mjolnir Configuration](/mjolnir/configuration) page. For the full step-by-step, revocation, and data-handling details — suitable for a security or ISO 27001 review — see the dedicated [Service Principal Setup](/platform/integrations/azure-devops-service-principal) guide. **Authentication vs authorisation.** Entra only authenticates the service principal; Azure DevOps decides what it can access through its own permission model. Least privilege is therefore enforced, and revocable, entirely on your side: remove the organisation membership or the repository permissions and Azure DevOps stops authorising the next request. Removing the federated credential stops any further token being minted, though one minted moments earlier remains valid until it expires. See [Revocation](/platform/integrations/azure-devops-service-principal#revocation) for the detail. ## Choosing the target repository However you connect, Odin saves a single target repository for the connection. The Azure DevOps card shows a green checkmark once the connection is active, and you can change the target repository at any time from the same card. ## Using Azure DevOps with Mjolnir Once Azure DevOps is connected, it becomes a source option when you set up a Mjolnir run. On the source step of the [Mjolnir setup wizard](/mjolnir/overview), you can pick a repository to scan, grouped by organisation and project, and choose the branch Mjolnir reads. When you have both GitHub and Azure DevOps connected, the wizard shows a provider toggle so you can choose which one this run uses. With only Azure DevOps connected, the wizard goes straight to the Azure DevOps repository picker. For pull-request feedback, enable [PR Reviews](/mjolnir/pr-reviews) per repository from the [Mjolnir Configuration](/mjolnir/configuration) page. Mjolnir then posts its review as comments and a `mjolnir-security-review` status check on each covered pull request. On a delegated connection, Odin registers the Azure DevOps Service Hooks that deliver pull-request events when you save the target repository, and re-registers them on every later save. If the authorising account cannot create subscriptions, the connection still works for pentesting, but PR reviews will not fire until a save succeeds with an account that can. ## Permissions What Odin can do depends on the connection model: * **Delegated (Entra OAuth)** — the token acts on behalf of the account that authorised the connection. Odin uses it to read repository contents and metadata for pentesting and, where PR Reviews are enabled, to post review comments and a status check. * **Service principal (federated)** — least privilege, scoped to the nominated repository: **Code (Read)** and **Contribute to Pull Requests**. Nothing else is requested or required. The access token is stored encrypted (Google Secret Manager), is short-lived, and is used only against the repository and pull requests you designate. ## Notes * Azure DevOps is a source-code connection for whitebox pentests and PR reviews. It does not track findings as issues. * Issue tracking is handled by Odin's other integrations. To sync findings into a tracker, connect [Linear](/platform/integrations/linear), [Jira](/platform/integrations/jira), [GitHub](/platform/integrations/github), or [GitLab](/platform/integrations/gitlab) alongside Azure DevOps. Work-item sync for Azure DevOps is coming soon. Today the connection covers repository access for whitebox pentesting and pull-request reviews. # Azure DevOps: Service Principal Setup Source: https://docs.borghq.io/platform/integrations/azure-devops-service-principal Connect Azure DevOps with a customer-owned service principal via workload identity federation — no shared secret This guide walks through connecting Azure DevOps to Odin using a **service principal you own** in your own Microsoft Entra ID tenant, authenticated via **workload identity federation (WIF)**. It is written for your platform and security teams and is intended to double as supporting evidence for an internal or ISO 27001 review of the integration. The short version: you keep full control of the identity, the credential, and the permissions. Borg never holds a client secret or certificate for your tenant, and every permission you grant can be reviewed and revoked entirely on your side, at any time. This is the **production security model**, recommended for enterprise and ISO 27001 / SOC 2 reviews. If you just want the quickest connection and are comfortable with delegated OAuth, see the [standard Azure DevOps integration](/platform/integrations/azure-devops) instead. Both give Mjolnir access to the same repositories. ## How it works The integration authenticates as a **service principal that you create and own**. The connection is **app-only** — there is no signed-in user and no delegated OAuth token. Rather than a client secret or certificate, the service principal trusts a **federated credential**. At connection time, Borg's GCP-hosted backend mints a short-lived, Google-signed OIDC token (issuer `https://accounts.google.com`) and presents it as the `client_assertion` in an OAuth2 `client_credentials` grant against your Entra tenant. Your tenant validates that token against the federated credential you configured and issues a short-lived Azure DevOps access token in return. The practical consequence: **Borg holds no client secret and no certificate** for your service principal, ever. There is nothing of that kind to store, rotate, leak, or revoke on our side — the only thing we hold is a short-lived access token, valid until its own expiry (see [Data handling](#data-handling)). The Google-signed assertion uses a **shared subject** (Borg's GCP service account) and an **Audience unique to your Odin organisation**. Entra matches Audience exactly, so a token minted for a different Odin organisation cannot authenticate as your app. Copy the Audience Odin displays; do not type Microsoft's default `api://AzureADTokenExchange` unless that is the exact value shown. ### Authentication vs authorisation The split of responsibility between the two systems is the basis for why this integration is low-risk and fully customer-controlled: * **Entra ID only authenticates the identity.** The federated credential lets your tenant confirm that a request really comes from Borg's GCP identity. It says nothing about what that identity is allowed to do. * **Azure DevOps authorises via its own permission model**, entirely independent of Entra. The permissions you grant the service principal are what actually constrain what the connection can do. Because authorisation lives entirely in Azure DevOps' own permission system, least privilege is enforced — and can be tightened, audited, or revoked — **entirely on your side**, without needing anything from Borg. ## What you will set up You will create three things, in this order. Odin shows you the exact federation values once you save the connection in step two, so keep the setup dialog open as you go. In the [Microsoft Entra admin centre](https://entra.microsoft.com), go to **App registrations → New registration**. Give it a dedicated name (e.g. `borg-odin-integration`), single-tenant, with no redirect URI. Register it. From the app's **Overview**, note the **Directory (tenant) ID** and **Application (client) ID**. **Do not** create a client secret or certificate — federation replaces them. A dedicated registration is recommended so its permissions can be scoped and audited independently of any other application. In Odin, go to **Management → Integrations**, click **Connect** next to Azure DevOps, and choose **Service principal**. Enter your **Tenant ID**, **Client (application) ID**, and **Azure DevOps organisation** (the `{org}` slug from `dev.azure.com/{org}`), then **Save**. Odin then displays the three federation values you need for the next step. Saving only stores the ids so Odin can show the federation values. Another organisation can save the same Tenant ID and Client ID until one of you successfully **Test connection**. After that, Save or Test will report that the service principal is already connected to another organisation. If the organisation already has a delegated OAuth connection to Azure DevOps, saving here replaces it: the stored configuration is rewritten in full, so no delegated token or refresh token is left behind. Back on the app registration, go to **Certificates & secrets → Federated credentials → Add credential**, and choose the **Other issuer** scenario. Fill in **exactly** the values Odin shows (use the copy buttons — no trailing spaces): | Field | Value | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | Issuer | `https://accounts.google.com` | | Subject identifier | The GCP service account unique numeric ID shown in the Odin setup dialog | | Audience | The **exact** Audience Odin shows. It includes your Odin organisation id. Do not use `api://AzureADTokenExchange` unless that is the value displayed. | Entra matches Audience character-for-character. If you re-save an older connection, Odin may show a new Audience — update the federated credential to that value before **Test connection**, or minting will fail. Give the credential a name and save. No client secret or certificate is created — this is what lets your tenant trust Borg's identity without any shared secret. Add the service principal as a member of your Azure DevOps organisation, then grant it — on the nominated repository only: * **Code (Read)** — clone the repository and read pull requests * **Contribute to Pull Requests** — post PR review comments and the status check No code-push or branch-write, no work-item access, and no organisation- or project-administration rights are required, and none should be granted. If the service principal does not appear when adding org members, check **Organization settings → Policies** for a service-principal / managed-identity access toggle and enable it. Back in Odin, click **Test connection**, which stays disabled until you have saved. Odin mints a token, counts the repositories the service principal can see in the organisation you nominated, and reports the total. A non-zero count confirms both the federation and the Azure DevOps permissions are correct. * *"Could not mint a token…"* → the federation values do not match; recheck the issuer, subject, and audience for typos or a trailing slash. * *"Token minted, but the service principal is not authorised…"* → federation works; the repository permissions from the previous step are missing or have not propagated yet. * *"Already connected to another organisation"* → another Odin organisation has already tested this Entra app successfully. Only needed if you want [PR Reviews](/mjolnir/pr-reviews) — skip it for pentest-only use. After you save, Odin also shows a **Webhook URL** and an **`X-Mjolnir-Token`** header value. Because a least-privilege service principal cannot register webhooks itself (that would require organisation subscription-admin rights), an Azure DevOps organisation admin registers them by hand: 1. In the project → **Project settings → Service hooks → + (Create subscription) → Web Hooks**. 2. Create one subscription triggering on **Pull request created**, and a second on **Pull request updated**. Odin lists the same two events by their Azure DevOps ids, `git.pullrequest.created` and `git.pullrequest.updated`. 3. For each, set the **URL** to the Webhook URL (copy the full value — it includes a query parameter), and paste the `X-Mjolnir-Token: …` string into the **HTTP headers** field. 4. Use the wizard's **Test** button to confirm Odin returns a `2xx`, then finish. Re-saving the connection reuses the same shared secret rather than minting a new one, so a hook you have already registered keeps working. You then enable PR reviews per repository from the [Mjolnir Configuration](/mjolnir/configuration) page. (The delegated OAuth model registers these hooks automatically; the service-principal model keeps them manual so the identity stays least-privilege.) ## Revocation You can revoke Borg's access unilaterally, at any time, without contacting Borg, by either: * **Removing the federated credential** from the service principal's app registration in Entra ID — Borg can then no longer authenticate as the service principal at all; or * **Removing the service principal from your Azure DevOps organisation** (or removing its permissions on the nominated repository) — authentication may still succeed, but Azure DevOps will no longer authorise any access. The two actions differ in when they bite. Taking away the service principal's Azure DevOps membership or repository permissions stops the very next request, because Azure DevOps authorises every call against its own permission model. Removing the federated credential stops us minting any further token, but a token minted shortly before you revoked stays valid until it expires, up to about an hour. Do both if you need access to stop within the minute. Either way there is no secret of ours to invalidate, because we never held one. ## Data handling * **Token lifetime** — minted Azure DevOps access tokens are short-lived (approximately one hour). Odin re-mints through the same federation flow once the cached token is within a minute of expiry, or as soon as a request comes back unauthorised. There is no long-lived refresh token, because `client_credentials` grants do not issue one. * **Minting failures** — if a mint fails, because the federated credential no longer matches or has been removed, the connection is marked **Token expired** and your Odin organisation is notified that Azure DevOps needs reconnecting. * **Storage** — minted access tokens are cached, encrypted, in Google Secret Manager, scoped to your organisation's integration record. No client secret or certificate is ever stored, because none is used. * **Scope of use** — tokens minted under this connection are used only within the Azure DevOps organisation you nominate, bounded by the least-privilege permissions you grant: cloning the nominated repository for a whitebox penetration test, and reading pull requests, posting review comments, and posting a pull-request status check as part of PR Reviews. No other Azure DevOps organisation is accessed under this connection. ## Permissions reference | Permission | Granted on | Why | | --------------------------- | ---------------------------- | ------------------------------------------------------------------------ | | Code (Read) | Nominated repository | Clone the repository for whitebox pentesting and read pull-request diffs | | Contribute to Pull Requests | Nominated repository | Post PR review comments and the `mjolnir-security-review` status check | | *(none)* | Organisation / project admin | Not required — hooks are registered manually by your admin | Everything else — code push, branch write, work-item access, and organisation or project administration — is neither requested nor required. ## Related * [Azure DevOps integration overview](/platform/integrations/azure-devops) — including the delegated OAuth alternative * [PR Reviews](/mjolnir/pr-reviews) — what Mjolnir posts on your pull requests * [Mjolnir Configuration](/mjolnir/configuration) — enabling PR reviews per repository # GitHub Integration Source: https://docs.borghq.io/platform/integrations/github Push findings to GitHub Issues Connect Odin to GitHub to push security findings directly to your repository's issue tracker. ## Connecting Go to **Management > Integrations** in the sidebar. Click **Connect** next to GitHub and authorise the Borg Security GitHub App. Choose the GitHub organisation or account that owns your repositories. Select the repository where issues should be created. Odin integrations page showing the GitHub connect flow ## Pushing a finding On any finding, click **Push to GitHub**. Odin creates a GitHub issue with: * Finding title as the issue title * Severity label (Critical, High, Medium, Low) * Full description, reproduction steps, and suggested fix in the issue body You can push multiple findings at once using the bulk action toolbar on the Findings page. ## Auto-linking pull requests to findings Once the GitHub App is installed, Odin automatically links pull requests to findings whenever a [finding identifier](/platform/findings#finding-identifiers-and-pr-linking) (like `BORG-12`) appears in the PR's branch name, title, or body. Linked PRs show as chips in the finding header, and their open/closed/merged state tracks live as the PR moves through GitHub. When a PR is linked to a **Reported** finding, Odin automatically transitions it to **Mitigating** so Borg's analyst team can see work is in progress. The fastest way to use this is the **Copy branch name** action on the finding detail header — it gives you a `fix/borg-12-...` style branch name ready to paste into `git checkout -b`. You can also link a pull request by hand from the finding's action menu. Linking a fix is what enables Odin to verify it when the PR merges. See [Automatic retests](/platform/automatic-retests) for all three linking methods and how verification works. ## Settings The GitHub integration has a few toggles that change how it works. Find them on the GitHub card in **Management > Integrations**. * **Issue tracking**: turn on to enable vulnerability tracking via GitHub Issues. When off, GitHub is used only for repository access (e.g. for Mjolnir whitebox pentesting). * **Auto-create tickets**: when on, GitHub issues are created automatically as new findings are reported. When off, you can still create issues manually from each finding. * **Minimum severity**: only findings at or above this severity trigger automatic issue creation. Defaults to Medium. * **Automatic retests**: when on, merging a pull request linked to a finding triggers a retest that reviews the merged code change and verifies whether the fix worked. See [Automatic retests](/platform/automatic-retests) for the full flow. Set the minimum severity to **High** or **Critical** if you want to keep your GitHub Issues focused on the most urgent findings and handle lower-severity issues manually. ## Customising synced issues With a target repository selected, the **Issue customization** panel on the GitHub card shapes the issues Odin opens. On top of the shared [default assignee and labels](/platform/integrations/overview#customising-synced-issues), GitHub adds: * **Milestone**: assign every synced issue to a repository milestone. The assignee, label, and milestone lists are read from the target repository, so you only see options that exist there. ## Status sync A finding's status and its linked GitHub issue's open/closed state and `odin:*` label stay in sync, in both directions. | Odin status | GitHub issue | | --------------------------------- | ---------------------------------------- | | Reported | Open, labelled `odin:reported` | | Mitigating | Open, labelled `odin:mitigating` | | Needs Revision | Reopened, labelled `odin:needs-revision` | | Open for Retest, Fixed & Retested | Closed | | Acknowledged | Closed as **not planned** | | GitHub issue event | Odin status | | -------------------------------------------- | --------------------- | | Closed | Open for Retest | | Reopened | Mitigating | | Labelled `odin:reported` / `odin:mitigating` | Reported / Mitigating | Closing as **not planned** doesn't acknowledge the finding from the GitHub side. Every closure moves the finding to **Open for Retest**, whatever the reason. Mark a finding **Acknowledged** from Odin instead. This is separate from the PR-auto-transition to Mitigating above, which fires when a PR is linked rather than when the issue itself changes. ## Notes * Issues are created in the repository(ies) accessible to the installed GitHub App * You can update the GitHub App's repository access at any time from your GitHub organisation settings # GitLab Integration Source: https://docs.borghq.io/platform/integrations/gitlab Push findings to GitLab Issues and grant Mjolnir code access Connect Odin to GitLab to push security findings into your GitLab issue tracker and, optionally, to grant Mjolnir read access to your projects for whitebox pentesting. ## Connecting Go to **Management > Integrations** in the sidebar. Click **Connect** next to GitLab and authorise the Odin app via GitLab's OAuth flow. Choose the GitLab project where issues should be created. ## Pushing a finding On any finding, click **Push to GitLab**. Odin creates a GitLab issue with: * Finding title and severity as the issue title * Description, reproduction steps, and suggested fix in the issue body * A link back to the finding in Odin You can push multiple findings at once using the bulk action toolbar on the Findings page. ## Settings The GitLab integration has a few toggles on the GitLab card in **Management > Integrations**. * **Issue tracking**: when on, vulnerability findings are tracked as GitLab issues. When off, GitLab is used only for project access (e.g. for Mjolnir whitebox pentesting). * **Auto-create tickets**: when on, GitLab issues are created automatically as new findings are reported. When off, you can still create issues manually from each finding. * **Minimum severity**: only findings at or above this severity trigger automatic issue creation. Defaults to Medium. Set the minimum severity to **High** or **Critical** if you want to keep your GitLab issues focused on the most urgent findings and handle lower-severity issues manually. ## Customising synced issues With a target project selected, the **Issue customization** panel on the GitLab card shapes the issues Odin opens. GitLab supports the shared [default assignee and labels](/platform/integrations/overview#customising-synced-issues): pick a project member to assign every synced issue to, and choose labels to add on top of the ones Odin already applies. Both lists are read from the target project. ## Status sync A finding's status and its linked GitLab issue's `odin:*` label stay in sync, in both directions, along with its open/closed state for some statuses. | Odin status | GitLab issue | | ---------------- | -------------------------------------------- | | Reported | Reopened, labelled `odin:reported` | | Mitigating | Labelled `odin:mitigating` (state unchanged) | | Open for Retest | Labelled `odin:retest` (state unchanged) | | Needs Revision | Reopened, labelled `odin:needs-revision` | | Fixed & Retested | Closed, labelled `odin:fixed` | | Acknowledged | Closed, labelled `odin:acknowledged` | | GitLab issue event | Odin status | | ------------------------------------------------------------ | --------------------------------------- | | Labelled `odin:reported` / `odin:mitigating` / `odin:retest` | Reported / Mitigating / Open for Retest | | Closed | Open for Retest | | Reopened | Mitigating | A newly added `odin:*` label always takes priority over a close/reopen on the same event. Closing or reopening an issue that already carries `odin:fixed`, `odin:acknowledged`, or `odin:needs-revision` is ignored, so it can't downgrade a Borg-set or Borg-staff-only status. ## Notes * Issues are created in the project you selected during setup * You can switch to a different project at any time from the Integrations page * Multiple issue trackers can be active at the same time. When you connect a second one (for example GitLab and Linear together), Odin keeps new findings and status changes in sync across all active trackers. # HackerOne Integration Source: https://docs.borghq.io/platform/integrations/hackerone Send bug bounty reports to Odin for HackerOne triage Connect your HackerOne program so every inbound report lands in Odin, where [HackerOne triage](/platform/bug-bounty-triage) can reproduce it against a live target before your team spends time on it. Every workspace can open **Testing → HackerOne** and the HackerOne card under **Management → Integrations**. Connecting a program is free; each triage run consumes credits. See [Bug bounty triage](/platform/bug-bounty-triage). HackerOne pushes reports to Odin over a webhook. Report states, comments, and bounty decisions stay in your program. ## What you need * Admin access to your HackerOne program's settings, so you can add a webhook and mint an API token. * The program handle is the slug in your program URL, so `acme` in `hackerone.com/acme`. * A read-only organisation API token, created in two short steps in HackerOne (the connect dialog walks through both): 1. A group with **Read only** on this program and **Asset inventory viewers**. 2. An API token added to that group. Odin uses it to list program assets and to fill in a report's asset when the webhook omitted it. ## Connecting Go to **Testing > HackerOne** and click **Connect HackerOne**, or go to **Management > Integrations** and click **Connect** on the HackerOne card. Both open the same form. Follow the two numbered steps in the dialog. Create a group (**Read only** on this program, **Asset inventory viewers** on assets), then create an API token and add it to that group. Type the program handle, the API token identifier (shown once when you created the token, not your email), and the token value. Odin verifies the token can see that program, then imports its assets with auto-triage off. Odin shows a webhook URL and a signing secret. The secret is shown once and never again, so copy both before you close the dialog. In your program's **Program settings > Webhooks**, create a webhook with the URL and secret from the previous step. Subscribe it to **Hacker submits report**, **Report is triaged**, and **Report is closed as resolved**. Reports start arriving as soon as you save the webhook. The first one usually shows up in the [HackerOne inbox](/platform/bug-bounty-triage) within seconds. Reports filed before you saved the webhook are not replayed — paste a report URL on the inbox to pull one in. Comment and bounty deliveries are ignored. Every comment fires a webhook carrying the full report, so Odin acts only on the three events above and answers everything else with an `ignored` response. An unexpected event type therefore shows up in HackerOne's own delivery log instead of passing silently. ## Program assets and auto-triage Ingesting a report is safe on its own. Triage won't touch a report until that HackerOne asset has a live http(s) URL and/or a bound GitHub repository, and you have authorised testing against it. Do that in the **Live targets** section of the HackerOne card. Connecting (or **Refresh from HackerOne**) lists every structured-scope asset on the program: * **HackerOne asset**: the identifier as HackerOne publishes it. Matching on inbound reports is exact. * **Live target URL**: where triage should send traffic. URL and DOMAIN assets are pre-filled when we can derive `https://…`. Optional if you bind a GitHub repo instead. * **Scope hosts**: the hosts triage is allowed to reach, comma-separated. Wildcards work: `api.example.com, *.example.com`. * **Auto-triage new reports**: off by default. Switching it on is consent to triage every new report on that asset. Needs a live URL or a GitHub repo. * **GitHub repo**: pick a repository already connected in Integrations. Alone that is whitebox; with a live URL it is graybox. Click **Save targets** when you're done. An asset with neither a live URL nor a GitHub repo stays untriageable, and the report page tells you which asset string to arm. ## Auto-triage With **Auto-triage new reports** on for an asset, a new report against that asset queues a triage run the moment it arrives. Nothing else triggers it: a triaged or resolved event updates the report in your inbox but never starts a run, and an asset without the switch waits for someone to press **Triage now**. A `report_created` webhook often omits structured scope. When that happens, Odin re-reads the report with your API token so the asset can still match. Auto-triage sends live traffic at the mapped target without anyone reviewing the report first, and each run [consumes credits](/platform/billing). Turn it on for an asset only once you're happy for every new report on it to be reproduced automatically. Odin caps how many auto-triage runs an organisation can have in flight at once. During a burst of submissions, a report that arrives over the cap is still ingested but doesn't start a run, so it sits in the inbox as **Untriaged** until someone presses **Triage now**. ## Reports filed before you connected The webhook only delivers reports submitted after you save it. To triage an older report, paste its HackerOne URL (or numeric id) on the [inbox](/platform/bug-bounty-triage) and click **Triage**. Odin fetches it with the same Read only API token and queues a run if that asset is already armed. If it isn't, the report still lands in the inbox so you can map the asset and press **Triage now**. ## Rotating the signing secret Every delivery is signed, and Odin rejects one whose signature doesn't match. Because the secret is only ever shown when it's created, rotation is the only way back from a lost secret. Click **Generate new secret** on the HackerOne card. The new secret appears once; paste it into your HackerOne webhook straight away. Deliveries signed with the old secret are rejected from the moment you rotate, so any report submitted in the gap won't reach Odin. ## Notes * The connection covers one program handle. Reports from another program aren't recognised. * Removing the connection stops ingest. Delete the webhook in HackerOne as well, otherwise your program keeps sending deliveries that are no longer accepted. * Findings from HackerOne triage are advisory. # Jira Integration Source: https://docs.borghq.io/platform/integrations/jira Push findings to Jira Connect Odin to Jira to push security findings into your project management workflow. ## Connecting Go to **Management > Integrations** in the sidebar. Click **Connect** next to Jira. You'll be redirected to Atlassian to authorise the Odin app. Choose the Jira Cloud site where issues should be created. Select the Jira project that should receive security findings. Odin integrations page showing the Jira connect flow ## Pushing a finding On any finding, click **Push to Jira**. Odin creates a Jira issue with: * Finding title as the issue summary * Severity mapped to Jira priority (Critical, High, Medium, Low) * Full description, reproduction steps, and suggested fix in the issue body You can push multiple findings at once using the bulk action toolbar on the Findings page. ## Auto-ticketing Auto-ticketing creates Jira issues automatically when new findings are reported, without any manual action from your team. From the integration settings panel: * **Auto-create tickets**: toggle on to enable. When disabled, you can still create issues manually from each finding. * **Minimum severity**: only findings at or above this severity trigger automatic issue creation. Defaults to Medium. Set the minimum severity to **High** or **Critical** if you want to keep your Jira board focused on the most urgent issues and handle lower-severity findings manually. ## Customising synced issues With your site and project connected, use the **Issue customization** panel on the Jira card to shape the issues Odin opens. On top of the shared [default assignee, labels, and priority mapping](/platform/integrations/overview#customising-synced-issues), Jira adds: * **Issue type**: the type Odin uses when creating issues, drawn from your project's issue types. If your project uses a custom type for security work (for example "Vulnerability" or "Security Bug"), pick it here. Leave it unset to use the project's default. * **Component**: assign every synced issue to a project component. Priority mapping turns each finding severity into one of your site's Jira priorities, and the label picker reads your site's labels (you can also type a label that doesn't exist yet). ## Status sync A finding's status and its linked Jira issue's status stay in sync, in both directions. | Odin status | Jira status | | -------------------------- | ----------- | | Reported | To Do | | Mitigating, Needs Revision | In Progress | | Open for Retest | In Review | | Fixed & Retested | Done | | Acknowledged | Won't Do | | Jira status | Odin status | | ------------------- | --------------- | | To Do | Reported | | In Progress | Mitigating | | In Review | Open for Retest | | Won't Do, Won't Fix | Acknowledged | Moving the issue to a generic **Done** status doesn't change the finding. Only Borg can set **Fixed & Retested**. Use **Won't Do** (or **Won't Fix**) to acknowledge a finding from Jira instead. Odin matches by status name first, so a site on the default Jira workflow gets the mapping above exactly. For a customised workflow, Odin falls back to matching the status's category (To Do, In Progress) where that's unambiguous. ## Notes * Issues are created in the project you selected during setup * You can switch to a different Jira project at any time from the Integrations page * Only Jira Cloud is supported. Jira Server and Jira Data Center are not currently available. * Multiple issue trackers can be active at the same time. When you connect a second one (for example Jira and Linear together), Odin keeps new findings and status changes in sync across all active trackers. # Linear Integration Source: https://docs.borghq.io/platform/integrations/linear Push findings to Linear Connect Odin to Linear to push security findings into your engineering workflow. ## Connecting Go to **Management > Integrations** in the sidebar. Click **Connect** next to Linear and authorise the Odin app via Linear's OAuth flow. Choose the Linear team where issues should be created. Odin integrations page showing the Linear connect flow ## Pushing a finding On any finding, click **Push to Linear**. Odin creates a Linear issue with: * Finding title and severity as the issue title and priority * Description, reproduction steps, and suggested fix in the issue body * A label indicating the source (e.g. `mjolnir`, `security`) You can push multiple findings at once using the bulk action toolbar on the Findings page. ## Auto-ticketing Auto-ticketing creates Linear issues automatically when new findings are reported, without any manual action from your team. From the integration settings panel: * **Auto-create tickets**: toggle on to enable. When disabled, you can still create issues manually from each finding. * **Minimum severity**: only findings at or above this severity trigger automatic issue creation. Defaults to Medium. Set the minimum severity to **High** or **Critical** if you want to keep your Linear board focused on the most urgent issues and handle lower-severity findings manually. ## Customising synced issues With your team selected, the **Issue customization** panel on the Linear card shapes the issues Odin opens. On top of the shared [default assignee, labels, and priority mapping](/platform/integrations/overview#customising-synced-issues), Linear adds: * **Initial state**: the workflow state new issues open in (Triage, Backlog, Todo, In Progress, and so on). Leave it unset to use your team's default. * **Project**: place every synced issue into a chosen Linear project. Priority mapping turns each finding severity into a Linear priority (Urgent, High, Normal, Low). The label picker reads your team's labels, with an option to show every workspace label or create a new one without leaving Odin. ## Status sync A finding's status and its linked Linear issue's workflow state stay in sync, in both directions. | Odin status | Linear state | | -------------------------- | ------------ | | Reported | Backlog | | Mitigating, Needs Revision | In Progress | | Open for Retest | In Review | | Fixed & Retested | Done | | Acknowledged | Cancelled | | Linear state | Odin status | | ------------ | --------------- | | Backlog | Reported | | In Progress | Mitigating | | In Review | Open for Retest | | Done | Open for Retest | | Cancelled | Acknowledged | Moving the issue to **Done** signals your fix is ready for Borg to verify, so it maps to **Open for Retest** rather than **Fixed & Retested**. Only Borg can confirm a retest. Odin matches by state name first, so a team on the default Linear workflow gets the mapping above exactly. For a customised workflow, Odin falls back to matching the state's underlying type (Backlog, Started, Completed, Cancelled). ## Notes * Issues are created in the team you selected during setup * You can update which team findings are sent to at any time from the Integrations page * If the team you selected is later retired in Linear, findings can't sync to it. Odin flags this as a **Sync error** on the Linear card so you can pick a new team to clear it — see [Sync health](/platform/integrations/overview#sync-health). * Multiple issue trackers can be active at the same time. When you connect a second one (for example Linear and Jira together), Odin keeps new findings and status changes in sync across all active trackers. # Integrations Overview Source: https://docs.borghq.io/platform/integrations/overview Connect an issue tracker and keep findings in sync Integrations push Odin's security findings into the issue tracker your engineers already use, so remediation work sits in the same backlog as everything else. Manage them all from **Management > Integrations** in the sidebar. The list opens on **GitHub**, with **HackerOne** next; cloud providers sit at the bottom for now. ## Supported trackers Odin pushes findings to five trackers. Each has its own connect flow and settings. Push findings into a Linear team Push findings into a Jira project Push findings to GitHub Issues Push findings to GitLab Issues Sync findings to Shortcut as stories GitHub and GitLab are dual-purpose: they also grant the repository access Mjolnir needs for whitebox pentesting. A connection can provide repository access without issue tracking, so turning on **Issue tracking** is a separate step on the integration's card. **Azure DevOps** is a repository-access connection for whitebox pentesting and [PR Reviews](/mjolnir/pr-reviews). It gives Mjolnir access to your Azure Repos but does not track findings as issues yet, so it isn't one of the trackers above. It can be connected either through delegated Entra OAuth or with a customer-owned service principal (workload identity federation) — see the [Azure DevOps integration](/platform/integrations/azure-devops) page for both connect flows. **HackerOne** is a report-ingest connection rather than a tracker. A Read only API token lists program assets; the program webhook delivers reports for HackerOne triage — see the [HackerOne integration](/platform/integrations/hackerone) and [Bug Bounty Triage](/platform/bug-bounty-triage). It doesn't create or sync issues. ## How findings reach your tracker There are three ways a finding becomes an issue in your tracker. * **Automatically**: with **Auto-create tickets** on, Odin opens an issue as soon as a finding is reported at or above your minimum-severity threshold. * **Per finding**: open any finding and click **Push to** your tracker. This works whether or not auto-create is on. * **In bulk**: the **Sync now** banner on the Integrations page creates issues for every finding that doesn't have one yet. **Shortcut is automatic-only.** There's no per-finding push button for Shortcut. Stories come only from auto-ticketing or **Sync now**. See the [Shortcut integration](/platform/integrations/shortcut) page. ## Syncing existing findings When you connect a tracker after findings have already been reported, those earlier findings have no external issue. The same gap appears if you turn a tracker on later or push some findings manually and leave the rest. Odin counts these gaps across every fully configured tracker and shows a banner at the top of the Integrations page. The banner has three states: If you have unsynced findings but no tracker is fully configured yet, the banner tells you how many findings are waiting and prompts you to finish setting up a connection. There's no sync button until a tracker is ready. Once at least one tracker is fully configured, the banner reports how many findings are missing an external issue and shows a **Sync now** button. Click it to create the outstanding issues across every ready tracker at once. After you sync, the banner confirms the jobs are queued. Issues are created in the background and appear in your tracker shortly. **Sync now** ignores the **Auto-create tickets** toggle. If you run trackers in manual mode, you can still use it to backfill issues on demand without turning auto-create on. A tracker counts as fully configured when its connection is active and its destination is set: a target repository for GitHub, a target project for GitLab, a team for Linear, a cloud site and project key for Jira, or a workflow for Shortcut. You can dismiss the banner. It stays hidden until the set of trackers with unsynced findings changes, then comes back when a new gap appears. ## Sync health If a connection develops a problem that blocks syncing — one only you can fix, such as the Linear team you selected being retired — Odin marks the tracker with a **Sync error** state on its card in **Management > Integrations** and explains what to correct. The status dot on the card turns red and reads **Attention needed**, so a broken tracker no longer looks healthy. Odin keeps the connection active and keeps trying: once you fix the underlying problem (for example, by choosing a new destination), the next finding that syncs clears the error on its own. Use [Sync now](#syncing-existing-findings) afterwards to backfill anything that didn't sync while the error stood. ## Status sync Once an issue is linked, status flows both ways: * **Odin to tracker**: when a finding's status changes in Odin, Odin moves the linked issue to match. That's the equivalent workflow state for Linear, Jira, and Shortcut, or an open/closed state plus an `odin:*` label for GitHub and GitLab. * **Tracker to Odin**: moving the linked issue to a different workflow state (or closing/reopening it, depending on the tracker) updates the finding's status in Odin. Your team can work entirely from the tracker and Odin stays in sync. **Fixed & Retested** is the one status the tracker can never set, whatever label or state name it uses. Only Borg staff can confirm it. See each tracker's page for its exact state, label, or workflow mapping. ## Assignee sync A finding's owner can travel with it. Assign a finding in Odin and its linked issue picks up the same person; reassign the issue in your tracker and the finding follows. Ownership stays consistent whether your team works from Odin or from the tracker. This rests on a mapping between your Odin teammates and their accounts in the tracker, so Odin knows which tracker user each teammate is. Set it up in the **Map your team** panel on the tracker's card in **Management > Integrations**, alongside the issue customisation settings. The panel lists every teammate next to a picker for their account in the tracker. Odin links people whose email matches automatically and suggests likely name matches for you to confirm, so most rows are filled in already and you just check them. Use **Refresh suggestions** after someone joins either side. GitHub doesn't expose member emails, so you link its rows by hand. Assigning or reassigning a finding sets the same person on its linked issue, for every tracker where the finding is linked and that person is mapped. Clearing the finding's assignee clears it on the tracker too. Reassigning the linked issue updates the finding's assignee to the mapped teammate. If the issue goes to someone who isn't mapped to an Odin user, the finding's assignee is left as it was. A mapped assignee also wins over the tracker's [default assignee](#customising-synced-issues): when Odin opens an issue for a finding that already has an owner, it uses that owner, and falls back to the default assignee only when the finding is unassigned or its owner isn't mapped. GitHub, GitLab, and Shortcut let an issue have several assignees; an Odin finding has one. Odin sets that single person on the issue, and reads the first assignee back when the change comes from the tracker. ## Customising synced issues Once a tracker is fully configured, an **Issue customization** panel appears on its card in **Management > Integrations**. It controls how a finding looks when Odin creates it as an issue. Leave any field unset to keep the tracker's default behaviour. These settings apply to every issue the tracker creates, whether it was opened automatically, pushed from a single finding, or backfilled with **Sync now** (Shortcut only ever creates issues automatically or via **Sync now**; see [above](#how-findings-reach-your-tracker)). A few controls are shared across every tracker: * **Default assignee**: pick a user, and Odin assigns every issue it creates to them, unless the finding already has a [mapped assignee](#assignee-sync). The list is drawn live from the connected tracker. * **Labels**: choose labels to apply to every synced issue, on top of the labels Odin already adds (such as `security` and the severity label). For Linear and Shortcut you can create a new label from the picker; for Jira you can type a label that doesn't exist yet. ### Priority mapping For Linear and Jira, the **Priority mapping** table lets you decide which tracker priority each finding severity becomes. Map Critical, High, Medium, and Low to the priorities your team uses, and leave a row unset to fall back to the tracker's default. Linear maps to its fixed Urgent/High/Normal/Low scale; Jira maps to whatever priorities your site defines. ### What each tracker offers The shared controls are joined by a few tracker-specific ones: | Setting | Linear | Jira | GitHub | GitLab | Shortcut | | ---------------- | ------ | ---- | ------ | ------ | -------- | | Default assignee | Yes | Yes | Yes | Yes | Yes | | Labels | Yes | Yes | Yes | Yes | Yes | | Priority mapping | Yes | Yes | — | — | — | | Initial state | Yes | — | — | — | Yes | | Project | Yes | — | — | — | — | | Issue type | — | Yes | — | — | — | | Component | — | Yes | — | — | — | | Milestone | — | — | Yes | — | — | See each tracker's page for the detail on its own settings. # Shortcut Integration Source: https://docs.borghq.io/platform/integrations/shortcut Sync findings to Shortcut as stories Connect Odin to Shortcut to keep security findings in sync with your team's Shortcut workspace. Shortcut works a little differently from Odin's other trackers: there's no manual **Push to Shortcut** button on a single finding. Stories are created through [auto-ticketing](#auto-ticketing) or a bulk [Sync now](/platform/integrations/overview#syncing-existing-findings) instead. ## Connecting Shortcut has no OAuth, so connecting uses a workspace API token instead of a redirect flow. Go to **Management > Integrations** in the sidebar. In Shortcut, go to **Settings > API Tokens** and create a token. Click **Connect** next to Shortcut and paste the token. Odin validates it against Shortcut before saving it. Choose the Shortcut workflow where Odin should create stories, and optionally a team to own them. The integration activates once a workflow is selected. ## Auto-ticketing Auto-ticketing creates Shortcut stories automatically when new findings are reported, without any manual action from your team. From the integration settings panel: * **Auto-create tickets**: toggle on to enable. When disabled, stories are only created via [Sync now](/platform/integrations/overview#syncing-existing-findings). * **Minimum severity**: only findings at or above this severity trigger automatic story creation. Defaults to Medium. Set the minimum severity to **High** or **Critical** if you want to keep your Shortcut workflow focused on the most urgent findings. ## Customising synced stories With a workflow selected, the **Issue customization** panel on the Shortcut card shapes the stories Odin opens. On top of the shared [default assignee and labels](/platform/integrations/overview#customising-synced-issues), Shortcut adds: * **Initial state**: the workflow state new stories open in, grouped by Unstarted, Started, and Done. Leave it unset to use the workflow's default. Shortcut doesn't support priority mapping: stories don't carry a priority field. ## Status sync A finding's status and its linked story's workflow state stay in sync, in both directions. | Odin status | Shortcut story state | | ------------------------------ | ----------------------------------------------------- | | Reported | Unscheduled (or the workflow's first unstarted state) | | Mitigating, Needs Revision | In Progress (or the workflow's first started state) | | Open for Retest | In Review (or the workflow's first started state) | | Fixed & Retested, Acknowledged | Done (or the workflow's first done-type state) | | Shortcut story state | Odin status | | ---------------------------------- | --------------- | | In Review | Open for Retest | | In Progress | Mitigating | | Any other **Unstarted**-type state | Reported | | Any other **Started**-type state | Mitigating | | Any other **Done**-type state | Open for Retest | Fixed & Retested and Acknowledged both move a story to the workflow's Done state, so there's no way to tell them apart from Shortcut alone. Moving a story back to a Done state always maps to **Open for Retest** in Odin, not Acknowledged. Only Borg can set **Fixed & Retested**, and an inbound change is ignored once a finding already has it. Odin matches by state name first (`In Review`, `In Progress`), then falls back to the state's type (Unstarted, Started, Done) for a customised workflow. ### Enabling status sync from Shortcut Shortcut has no webhook API of its own, so status changes only flow from Shortcut back into Odin once you set up an outgoing webhook by hand: On the Shortcut card in **Management > Integrations**, copy the webhook URL shown under **Status sync**. In Shortcut, go to **Settings > Integrations > Outgoing Webhook**, paste the URL, and set a signing secret. Paste the same secret back into the Shortcut card and save. Odin uses it to verify that inbound requests really came from Shortcut. Until the secret is saved, moving a story in Shortcut has no effect on the linked finding. Outbound status pushes from Odin to Shortcut aren't affected. ## Notes * Stories are created in the workflow (and team, if selected) you chose during setup. Change either at any time from the Integrations page. * Multiple issue trackers can be active at the same time. When you connect a second one (for example Shortcut and Linear together), Odin keeps new findings and status changes in sync across all active trackers. # Alert Centre Source: https://docs.borghq.io/platform/notifications Stay on top of security events with in-app notifications The Alert Centre is your in-app notification inbox. It surfaces events across your organisation: new findings, status changes, completed reports, new assets discovered, team changes, and more. Open the Alert Centre by clicking the bell icon in the top navigation bar. The bell shows a red indicator when there are unread notifications. ## Notification types Odin generates notifications for the following events: | Event | Description | | ----------------------------- | --------------------------------------------------------------- | | **New finding created** | A new security finding has been identified | | **Finding status changed** | A finding's status was updated (e.g. Reported → Mitigating) | | **Finding assigned** | A finding was assigned to you | | **Report delivered** | A new pentest report revision is ready to view | | **Pentest status changed** | A pentest engagement started, completed, or changed state | | **New asset discovered** | Continuous Asset Discovery found a new domain, subdomain, or IP | | **CAD scanning paused** | Continuous Asset Discovery scanning was paused on an asset | | **CAD scanning resumed** | Scanning has resumed on an asset | | **Mjolnir run paused** | A Mjolnir run was paused mid-flight | | **Integration token expired** | An integration's OAuth token expired and needs reconnecting | | **Discussion message** | Someone replied or mentioned you in a finding discussion | | **Member joined** | A new member joined the organisation | | **Member left** | A member was removed or left | | **Member role changed** | A member's role was updated | ### Billing and credits Billing events raise their own notifications. These go to every member of the organisation in the Alert Centre, and the ones that need someone to act are also emailed (see [Email notifications](#email-notifications)). | Event | Description | | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **80% of plan credits used** | Your remaining plan credits dropped below a fifth of the period's allowance. Sent once per billing period | | **Out of plan credits** | The period's plan credits are used up. Runs continue against your adhoc balance or your tier's credit debt | | **Credit-debt limit reached** | You have used the plan credits plus all the credit debt your tier allows, and runs are blocked until you top up or upgrade. Enterprise plans have no debt limit, so they never see this | | **Auto Deposit topped up** | An automatic top-up succeeded, with the number of adhoc credits added | | **Auto Deposit failed** | The saved card was declined. Automatic top-ups stay paused until you retry or replace the card | | **Plan payment failed** | A plan invoice could not be collected. Runs are blocked until the payment is recovered | | **Plan activated** | A plan was purchased or an enterprise plan was switched on, and its credits are ready to use | | **Plan upgraded** | An upgrade took effect, with the tiers it moved between. The extra plan credits are available straight away | | **Plan downgrade scheduled** | A downgrade was booked for the end of the current period, with the target tier and date | | **Plan downgrade applied** | The downgrade took effect. If the new tier's workflow cap is lower than your number of active workflows, the message says how many were switched off | | **Plan cancellation scheduled** | A cancellation was booked for the end of the current period, with the date | | **Plan cancelled** | The plan ended | | **Adhoc credits frozen** | Cancelling the plan froze your remaining adhoc credits, with the amount held | | **Frozen credits expiring soon** | Frozen adhoc credits are close to their six-month deadline. Sent 30 days out and again 7 days out | | **Frozen credits expired** | Frozen adhoc credits passed the six-month deadline and were written off | | **Adhoc credits restored** | Reactivating a plan within the six-month window returned frozen credits to your spendable balance | [Billing](/platform/billing) covers the plans, Auto Deposit and frozen credits these events report on. Finding-related notifications — **New finding created**, **Finding status changed**, and **Discussion message** — go to that finding's [followers](/platform/findings#following-findings), not the whole organisation. See [Default finding subscribers](/platform/organisation-settings#default-finding-subscribers) for who follows a finding by default. [Following a finding](/platform/findings#following-findings) — by clicking **Follow**, commenting on it, being `@mentioned`, or being assigned — means status changes and discussion replies on it arrive as immediate Alert Centre entries. If you've only been subscribed automatically as a [default subscriber](/platform/organisation-settings#default-finding-subscribers) and haven't otherwise engaged with the finding, its routine updates arrive in your [weekly summary](#weekly-summary) instead. Assignment and @mentions always send an immediate alert. ## Grouped notifications When several findings are reported or updated at once — for example when a pentest report is delivered — the Alert Centre shows a single grouped entry instead of one notification per finding, such as "12 findings reported". Select **Show findings** on a grouped entry to expand the list of findings it covers. Each one links through to the finding itself. ## Weekly summary Odin bundles status changes and discussion replies into a weekly summary — one email plus a matching Alert Centre entry — recapping activity across every finding you follow. * **When it arrives**: Monday morning, covering the previous week's activity. * **What it covers**: status changes and discussion replies across every finding you follow. It's the primary way you'll hear about findings where you're only a [default subscriber](/platform/organisation-settings#default-finding-subscribers) and haven't otherwise engaged, since those don't send an immediate alert. * **What's excluded**: assignments and @mentions always send an immediate alert and are never held back for the weekly summary. * **Opting out**: turn off the weekly summary from your [profile](/platform/profile#weekly-summary). ## Email notifications On top of the Alert Centre, a few events also send an email, so you don't need to be watching the inbox to catch them: * **Assigned to you**: you're emailed when a finding is assigned to you. * **Retest failed**: if a finding assigned to you is retested and moves to **Needs Revision**, you're emailed. * **Critical in a delivery**: when a batch of newly reported findings includes at least one **Critical**, your organisation's [default finding subscribers](/platform/organisation-settings#default-finding-subscribers) are emailed. * **Weekly summary**: a Monday-morning email recapping routine activity on every finding you follow — see [Weekly summary](#weekly-summary) above. Aside from the billing emails below, every other notification type stays in the Alert Centre only, with no separate email. This includes routine status changes and discussion replies: if you [actively follow](/platform/findings#following-findings) the finding, you get an immediate Alert Centre entry; if you're only a default subscriber who hasn't otherwise engaged with it, the update is rolled into the weekly summary instead. Assignments and @mentions are the exception — they always notify you immediately and by email. ### Billing emails Billing events someone has to act on also send an email: **Credit-debt limit reached**, **Auto Deposit failed**, **Plan payment failed**, **Plan activated**, **Plan downgrade scheduled**, **Plan downgrade applied**, **Plan cancellation scheduled**, **Plan cancelled**, **Frozen credits expiring soon**, **Frozen credits expired**, and **Adhoc credits restored**. Each one links back to your billing page. These go to your organisation's billing email address and to every Owner and Admin, since they are the people who can update a card or change a plan. The rest stay in the Alert Centre: the low-credit and out-of-credit warnings, successful Auto Deposits, plan upgrades, and credits being frozen. ## Slack notifications If you've connected Slack, the connected channel receives **new findings**, **retest failures**, and **finding assignments**, plus a single **weekly summary** post covering that week's digest. Routine status changes and discussion replies on findings you follow — whether from your organisation's members or the Borg security team — don't post to Slack individually; they're covered by the weekly summary post instead. The other notification types above stay in the Alert Centre only. From **Management > Integrations**, the Slack card's **Channel overrides** let you route individual notification types to a channel other than your default — for example, sending **Finding assigned** posts to a separate channel from new findings and status changes. ## Filtering Use the tabs at the top to switch between **All** notifications and **Unread** only. The unread tab shows a count so you can see how many items need attention. ## Managing notifications * **Mark as read**: hover an unread notification and click the tick icon to mark it read without leaving the inbox * **Mark all as read**: the button above the list clears every unread notification in one go, and greys out when you have nothing unread * **Mark several at once**: hover a notification to reveal its checkbox, tick the ones you want, then choose **Mark selected as read**. Use **Clear selection** to drop your picks without changing anything * **Click to navigate**: clicking a notification opens the item it refers to (a finding, report, Mjolnir run, or asset) and marks it read on the way through # Odin MCP Server Source: https://docs.borghq.io/platform/odin-mcp Give Cursor and other coding agents safe, GitHub-first remediation context The Odin MCP server connects your coding agent to your organisation's security data. Ask Cursor, Claude, Codex, or another [Model Context Protocol](https://modelcontextprotocol.io) client about a finding such as `ODI-12`, inspect its remediation guidance, create the code change and pull request yourself, then ask Odin to link the existing pull request and report the retest. Odin is organisation-scoped and GitHub-first. It provides context and workflow operations; it never creates commits, pushes branches, or creates pull requests. The server is published on npm as [`@borgresearch/odin-mcp`](https://www.npmjs.com/package/@borgresearch/odin-mcp). It runs locally as a subprocess of your client, talks to the public Odin API, and authenticates with an [API key](/platform/api-keys). You need Node.js 24 or newer on your `PATH`. A **Read only** key is enough to discover findings, read remediation context, and inspect retest history. Choose **Read & Write** when the agent must update a status or link an existing pull request. To update an existing setup, change the package in your client config to `@borgresearch/odin-mcp@latest` and restart the client. For a global install, run `npm install -g @borgresearch/odin-mcp@latest`. ## Setting up Go to **Workspace > API Keys** and create a key. The dialog defaults to **Read & Write** for the remediation workflow, but **Read only** remains available when the agent should only inspect data. The full key is shown once, so copy it before closing the dialog. Expand **Setup guide: connect an AI agent** on the API Keys page and copy the snippet for your client. If you've just created a key, the snippet already has it filled in. Most clients only read their MCP configuration at startup. After restarting, check the client's list of MCP servers for `odin` and confirm it reports nine tools. Try: *"Explain `ODI-12`, show me the suggested branch, and tell me what I need to do before opening a PR."* ## Client configuration Replace `odin_...` with your own key in each snippet. Add to your project's `.cursor/mcp.json`, or open **Settings › MCP** and add a new server. ```json theme={null} { "mcpServers": { "odin": { "command": "npx", "args": ["-y", "@borgresearch/odin-mcp@latest"], "env": { "ODIN_API_KEY": "odin_..." } } } } ``` Add to `claude_desktop_config.json`, then restart Claude Desktop. ```json theme={null} { "mcpServers": { "odin": { "command": "npx", "args": ["-y", "@borgresearch/odin-mcp@latest"], "env": { "ODIN_API_KEY": "odin_..." } } } } ``` ```bash theme={null} claude mcp add --transport stdio --env ODIN_API_KEY=odin_... odin -- npx -y @borgresearch/odin-mcp@latest ``` Add to `~/.codex/config.toml`, then restart Codex. ```toml theme={null} [mcp_servers.odin] command = "npx" args = ["-y", "@borgresearch/odin-mcp@latest"] env = { ODIN_API_KEY = "odin_..." } ``` Point the client at `npx -y @borgresearch/odin-mcp@latest` and pass `ODIN_API_KEY` in its environment. See the [package README](https://www.npmjs.com/package/@borgresearch/odin-mcp) for client-specific paths. ## Tools Every tool returns a readable Markdown summary and a structured payload. Human identifiers are organisation-local; `ODI-12` is preferred, while the internal ID remains available for chaining. | Tool | Permission | What it does | | --------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | `list_findings` | Read | Lists findings with pagination, current status, severity, repository, and identifier/title search | | `get_finding` | Read | Returns bounded remediation context, revision content, suggested branch, linked PRs, workflow blockers, and latest retest state | | `update_finding_status` | Read & Write | Moves a finding to Mitigating, Open for Retest, or Acknowledged | | `link_finding_pull_request` | Read & Write | Links one existing accessible GitHub PR; it does not create or change the PR | | `get_finding_retests` | Read | Reads retest history without triggering a retest or spending credits | | `list_pentests` | Read | Lists pentests for the organisation | | `get_pentest` | Read | Fetches a pentest's status, schedule, and scope | | `list_assets` | Read | Lists attack-surface assets with filters and pagination | | `get_asset` | Read | Fetches an asset and the findings that reference it | ### Finding references Use the human identifier shown in Odin: ```text theme={null} ODI-12 ``` The prefix is an alias, not a global namespace. Odin resolves the numeric suffix only inside the organisation belonging to the API key and always returns the finding's canonical stored identifier. A reference from another organisation is not revealed through an error. Internal finding IDs are supported when chaining results between tools. ### Remediation flow 1. Ask `get_finding` about `ODI-12`. 2. Read the remediation, code reference, workflow blockers, and `suggestedBranch` (for example, `fix/odi-12-sql-injection-in-login-form`). 3. In Cursor or your normal development environment, create that branch, make and test the change, commit it, push it, and open the GitHub PR yourself. 4. Explicitly ask the agent to use `link_finding_pull_request` with the existing PR URL. Odin verifies the PR through your organisation's GitHub App installation and stores authoritative metadata. Linking the same PR again is safe and idempotent. 5. When the linked PR merges, GitHub webhook processing may queue an automatic retest if the organisation's GitHub and retest prerequisites are ready. Use `get_finding_retests` to distinguish no history, queued/running, completed, skipped, and failed runs. Odin does not infer permission from a matching PR and agents should not mutate a finding merely because a URL or identifier looks correct. Ask before linking a PR or changing status. ### Updating a finding's status `update_finding_status` needs an API key with **Read & Write** permission. Cookie-authenticated dashboard requests also need a member role or higher: | Status | Use it when | | ----------------- | --------------------------------- | | `MITIGATING` | You have started work on the fix | | `OPEN_FOR_RETEST` | The fix is ready for verification | | `ACKNOWLEDGED` | You accept the risk for now | `NEEDS_REVISION` and `FIXED_AND_RETESTED` are set by Borg's retest process and are not client-writable. ### Retests `get_finding_retests` is read-only. It never calls the manual retest endpoint, queues work, or spends credits. A completed retest exposes its sanitised verdict and status action without billing fields. Automatic retests are merge/webhook-driven; see [Automatic Retests](/platform/automatic-retests). ## Permissions and scoping Every call is scoped to the single organisation that owns the API key. If you belong to several organisations, create one key per organisation and register each as a separate MCP server, such as `odin-acme` and `odin-internal`. * **Read only**: discovery, finding remediation context, linked-PR discovery, and retest reads. * **Read & Write**: all Read-only actions plus status changes and linking an existing accessible GitHub PR. * **Member role**: required for status changes and PR-link mutations from a cookie-authenticated dashboard request. MCP API-key calls are authorised by the key's Read & Write permission. The API key does not grant repository access beyond the organisation's configured GitHub App installation. A PR in an inaccessible repository is rejected without creating a link. ## Rate limits Each key is limited to 100 requests per minute. `429` responses include retry guidance. ## Troubleshooting Check the key under **Workspace > API Keys**, confirm the client config sets `ODIN_API_KEY`, and restart the client. Most clients only reload MCP configuration at startup. The agent attempted a status change or PR link with a Read-only key. Create a new **Read & Write** key; permissions on an existing key are not silently upgraded. Confirm the human identifier, and remember that identifiers and API keys are organisation-scoped. A different organisation's finding is intentionally indistinguishable from an unknown finding. The organisation's retest automation capability is gated or not configured. This does not allow the MCP to trigger a manual retest; check the GitHub and automatic-retest settings. Check the client's MCP logs and restart it after changing configuration. The server needs Node.js 24 or newer. Create, scope, and revoke the keys the server authenticates with Understand merge-driven verification and retest outcomes # Organisation Settings Source: https://docs.borghq.io/platform/organisation-settings Configure your organisation's name, discussion notifications, finding identifier, verified domains, and single sign-on Organisation Settings is where Admins control how the workspace operates: the organisation name, how email notifications for finding discussions behave, the prefix used in finding identifiers, the domains you have proved you own, and single sign-on. Open it from the sidebar under **Workspace**, or from the user menu. Only **Admin** and **Owner** roles can edit organisation settings. Other members see a read-only view of the same information. ## General information The general section shows your organisation's name and discussion notification defaults. ### Organisation name The display name for your organisation, visible to all members throughout the platform. Admins can change it at any time. Saving requires [step-up verification](/platform/step-up-verification). ### Discussion reply emails When someone (Borg or a teammate) replies in a finding's [discussion thread](/platform/findings#discussion-and-activity), Odin can send an email so you don't miss it. * **Discussion reply emails (toggle)**: when on, all members receive emails for new discussion replies on findings, unless overridden by each user in their [profile](/platform/profile). When off, no emails are sent by default — only users who opt in via their profile receive them. * **Minimum severity for reply emails**: only findings at or above this severity trigger reply emails. Defaults to all severities. Mentions (e.g. @alice) always send an email, regardless of severity threshold or the organisation default. ## Finding identifiers Every finding in your organisation gets a unique identifier like `ACME-42`. The prefix (`ACME`) is your **finding prefix** — choose something short and memorable, typically your organisation's abbreviation. The prefix can be set once during onboarding and changed afterwards. Changing it renumbers nothing — existing findings keep their identifiers, new findings use the new prefix going forward. Saving a new prefix requires [step-up verification](/platform/step-up-verification). ## Default finding subscribers Owners and Admins choose who is subscribed automatically when a new finding is reported, from the **Default finding subscribers** setting: * **All members** — every member is subscribed automatically, except **Read only** users. This includes people who join the organisation later. * **Custom** — only a selected list of members is subscribed automatically. This only sets the starting subscriber list for new findings. Individuals can still [follow or unfollow](/platform/findings#following-findings) specific findings themselves, regardless of the default. ## Verified domains The **Verified Domains** card is where you prove you own an email domain with a **DNS TXT record**. Verifying one unlocks [single sign-on](#single-sign-on) and automatic team joining for the people who use that domain. Mjolnir pentest setup can also prove a scan target with a file or CNAME. That is only authorisation to test the domain — it does **not** enrol it for single sign-on. Those rows stay on this list as **Verified** with a **Pentest only** badge. Publish the TXT record shown on the row and select **Re-check**. Odin keeps the pentest proof if the TXT record is not there yet. Only Owners and Admins can see and manage this card. Type the domain (for example `example.com`) and select **Add domain**. It appears in the list marked **Pending**, with the DNS record you need to publish. Copy the **Type**, **Name** and **Value** fields onto your DNS provider as a TXT record. Each field has its own copy button. Select **Re-check** on the row. Odin looks up the record and flips the badge to **Verified**. On a **Pentest only** row it looks for the TXT record and, if it is there, drops that badge so the domain can be used for single sign-on. DNS changes usually appear within a few minutes, so if the badge still reads **Not found**, wait a moment and check again. If your DNS provider supports [Domain Connect](https://www.domainconnect.org/), Odin offers to publish the record for you instead. A panel appears above the manual instructions reading **Add the record with Cloudflare** (or **Add the record automatically** for other providers). Select it, approve the request at your provider, and Odin re-checks the domain when you come back. Each row carries a status badge: **Verified** (DNS TXT, ready for single sign-on), **Verified** plus **Pentest only** (Mjolnir file or CNAME), **Pending** while the record is not visible yet, or **Not found** when the last lookup failed. Removing a verified domain disables the features that depend on it, including single sign-on and automatic team joining. Odin asks you to confirm first. ## Single sign-on The **Single Sign-On** card lets your team sign in through your own identity provider over SAML or OIDC. It needs a verified domain and an **Enterprise** plan. On pay-as-you-go the card explains this and offers **Contact the team about single sign-on**, which opens a message to Borg — the same path as enabling agentic whitebox. Only Owners and Admins can configure it. Other members see the connection's status, or a note saying an administrator can set it up. ### Connecting an identity provider The card shows the values to enter on your side first: the **ACS (Single Sign-On) URL** and **SP Entity ID / Audience** for SAML, or the **Redirect URL** for OIDC. Copy those into the application you create in your identity provider, then fill in the Odin form: * **SAML**: give Odin either an **IdP metadata URL** or the **metadata XML** pasted in full * **OIDC**: give Odin the **discovery URL**, **client ID** and **client secret** * **Display name** (optional): a label such as `Okta`, shown wherever the connection appears * **Verified domains**: tick every domain whose users should sign in through this connection. At least one is required. Only domains verified with a DNS TXT record are listed — a Mjolnir file or CNAME check is not enough. Select **Connect identity provider** to save. The card then shows the connection with its type, status and sign-in domains. ### Managing a connection Once a connection exists, Admins can: * **Disable** it temporarily, and **Enable** it again later. A disabled connection stops routing sign-ins without losing the configuration. * **Reconfigure** it to change the metadata, credentials or domains. * **Remove** it entirely. Members who signed in through it fall back to a one-time code. Single sign-on relies on a service Borg runs for your environment. Until it is provisioned the card explains this and the form stays read-only. ## Organisation overview A summary card shows key details about your organisation: * **Members**: the current member count, with a link to [Team Management](/platform/team-management) for admins * **Status**: your organisation's current status * **Products**: which products are active on your subscription * **Created**: when the organisation was created ## Domain join If your organisation has **domain join** enabled, anyone with an email address matching your allowed domain(s) can join automatically without an invitation. Domain join is configured by Borg as part of onboarding. It appears as a read-only field on the General Information card. Contact [mail@borghq.io](mailto:mail@borghq.io) if you need it enabled or changed. Domain join is separate from the [verified domains](#verified-domains) list: verified domains are the ones you have proved you own, and they are what single sign-on is bound to. Domain join is powerful — anyone with a matching email can join. We only enable it for verified company domains, never for shared providers like `gmail.com`. ## Legal and agreements The **Legal & Agreements** card links the documents that govern your use of the platform: * **Master Services Agreement**, **Data Processing Agreement**, and **AI Services Addendum** — the agreements an Owner accepted during onboarding, opening as PDFs * **Privacy Policy** and **Subprocessors** — the in-app policy pages Every member can open these links, regardless of role. The same documents are also collected on the [`/legal`](/getting-started/terms-of-service#finding-the-agreements-later) page. # Pay as you go Source: https://docs.borghq.io/platform/pay-as-you-go Buy credits up front and spend them as services run Some organisations are set up to pay for credits directly instead of subscribing to a plan. If yours is one of them, Billing has two tabs rather than the plan tabs: **Overview** for balance, top-ups and payment methods, and **Usage** for credit consumption over time. There is no plan picker and no recurring plan credits. You buy credits when you need them, and each completed service run draws them down. New self-serve workspaces start on prepaid pay as you go and pay by card. Older organisations that were billed after usage, or that sit on a plan, keep that arrangement — you cannot switch between them from inside Odin. If you see the five plan tabs described in [Billing](/platform/billing), your organisation is on a plan instead. ## Credit balance Overview opens on a **Credit balance** card — the same kind of wallet used on plan billing, adapted for prepaid credits. The left side is the number of credits you have left. The right side is **Add credits**, so you can top up without leaving the card. The page does not show a per-credit rate. Credits don't expire while your organisation is active. They are deducted when a completed service event is recorded, not when a run starts. HackerOne triage draws the same prepaid wallet as PR review and other billable work. If your balance reaches zero, a note under the number tells you to add credits to run billable work. You can still sign in and look around Odin; only billable services are held back. A banner appears if a payment failed and the outstanding amount is still being recovered; new billable work stays paused until it clears. ## Adding credits **Add credits** lives on the balance card. It takes an amount in your account currency rather than a number of credits. Pick one of the preset amounts or type your own, then click **Add credits**. Presets cover the common cases; the input accepts any amount above zero. If your billing details are already on file, the card charges your saved payment method. If they aren't, you're sent to Stripe Checkout, which collects your billing address and tax ID first. Credits land once the payment confirms, so the balance may take a moment to move. Applicable tax is added on top of the amount you enter. ## Auto Top-Up Auto Top-Up sits at the bottom of the same card as a switch. Turn it on to buy credits when the balance runs low, so a scheduled run doesn't stall overnight. **Set amounts** / **Change amounts** opens the two money fields: * **Below**: the balance that triggers a purchase * **Add**: how much to charge each time it triggers It charges the card already saved under **Payment methods**. Add a card there first if you don't have one. A failed charge pauses Auto Top-Up and expands that section with an alert. **Retry now** clears the pause and tries again after the next deduction; you can also top up by hand in the meantime. Plan-based organisations have a similar feature called Auto Deposit, which works in credits rather than cash. See [Billing](/platform/billing#auto-deposit). ## Usage The **Usage** tab — also at `/billing/usage` — shows credit consumption over time, broken down by product. Top-ups stay on Overview; this tab is for what you spent, not what you bought. ## Recent top-ups **Recent top-ups** lists your five most recent credit purchases with the date, how they were triggered, and the amount paid. Each one is labelled **Manual top-up**, **Auto Top-Up**, or **Balance recovery** for a charge that cleared an outstanding amount. If you have not bought credits yet, the table says so. Service usage is on the Usage tab. ## Payment methods and seats These sit as two cards under the wallet. You can add and remove cards under **Payment methods**, where Stripe handles the card details so they never reach our servers. **Seats** shows how many seats are in use and lets an admin invite members or add seats. Five seats are included at no extra charge; extra seats are billed monthly. ## Invoiced usage A small number of older pay-as-you-go accounts are still billed after the fact rather than from a prepaid balance. Those organisations keep working as they always have; new sign-ups do not use this path. That version keeps the same Overview and Usage tabs. Overview shows the credit balance and funding path as **Invoice after usage**; Usage adds a **Usage history** list with one row per completed service event: what ran, when, the credits it consumed and the amount charged. A failed payment banner on Overview links through to Usage so you can retry from the matching row. Each row carries a status: | Status | Meaning | | ------------------------------ | ---------------------------------------------------------------------- | | **Pending collection** | Recorded, waiting to be invoiced | | **Open** | Invoiced, not yet paid | | **Covered by balance** | Paid out of credits you already held | | **Deferred small amount** | Too small to charge on its own; carried forward rather than rounded up | | **Added to customer balance** | Rolled into your Stripe customer balance | | **Paid** | Settled | | **Action required** | Your bank needs to confirm the payment | | **Payment failed** | The charge didn't go through | | **Voided** / **Uncollectible** | Written off; no payment is expected | Where a charge failed, admins get a **Retry payment** button on the row, and any row with an invoice behind it links out to Stripe's hosted invoice page. # Profile & Security Source: https://docs.borghq.io/platform/profile Manage your profile information, passkeys, linked accounts, and notification preferences The Profile page lets you update your personal information, manage sign-in methods, and control how you receive email notifications. Open it from the user menu in the top-right corner by clicking **Profile**. Use the list on the left to open a section: profile, passkeys, linked accounts, Slack (when relevant), and notifications. On smaller screens the list sits above the panel as a row of links. ## Profile ### Name Your first and last name appear throughout the platform: in comments, activity feeds, and team lists. Update them here and click **Save Changes**. Saving your profile requires [step-up verification](/platform/step-up-verification) to confirm your identity. ### Email Your email address is shown under your name for reference and cannot be changed. It's tied to your authentication and is the address where OTP codes and notifications are sent. ### Profile picture Upload a profile picture so your team can identify you across the platform. Click your avatar or **Upload** to select an image. * **Formats**: PNG or JPEG * **Max size**: 2 MB * **Remove**: click the remove icon on your current picture and confirm ## Passkeys Passkeys let you sign in with biometrics (fingerprint, Face ID) or a hardware security key instead of an email OTP code. They're faster and more secure than one-time codes. ### Adding a passkey 1. Open **Passkeys** from the list on the left 2. Click **Add new passkey** 3. Follow your browser or device prompt to register the passkey (e.g. Touch ID, Windows Hello, or a USB security key) 4. Give the passkey a name so you can identify it later You can register multiple passkeys, for example one on your laptop and another on your phone. ### Removing a passkey Click **Remove** next to any passkey and confirm. You'll need to complete [step-up verification](/platform/step-up-verification) before the passkey is deleted. If you remove all your passkeys, you'll need to use the email OTP flow to sign in. ## Linked accounts If you've signed in with an external provider (e.g. Google), the **Linked accounts** section shows the connection so you can see which third-party identities are tied to your Odin account. ## Notifications The **Notifications** section controls whether you personally receive emails when there's a new reply in a finding's discussion thread. Your preferences override the organisation default set in [Organisation Settings](/platform/organisation-settings). * **Receive discussion reply emails**: when on, you get emails for replies on findings at or above your chosen severity. When off, you receive nothing — even when the organisation default is on. * **Minimum severity**: only get emails for findings at or above this severity (Low, Medium, High, or Critical). Mentions (e.g. @you) always send an email, regardless of these preferences or the organisation default. They override every threshold. ## Weekly summary Odin bundles routine activity — status changes and discussion replies — into a [weekly summary](/platform/notifications#weekly-summary) recapping every finding you follow: one email plus an Alert Centre entry, sent Monday morning. It's the primary way you'll hear about findings where you're only a [default subscriber](/platform/organisation-settings#default-finding-subscribers) and haven't otherwise engaged, since those don't send an immediate alert. * **Receive weekly summary**: on by default. Turn this off if you'd rather not get the digest email and Alert Centre entry. Turning this off only affects the weekly summary. Findings you actively follow — by clicking Follow, commenting, being @mentioned, or being assigned — still notify you immediately in the Alert Centre, and assignments and @mentions always email you too. Learn about Odin's authentication methods # Reports Source: https://docs.borghq.io/platform/reports Download and share pentest reports from Odin The Reports page is your library of delivered pentest reports. Open it from **Management > Reports** in the sidebar. A report appears here once the Borg team delivers it. Delivery also raises a **Report delivered** entry in your [Alert Centre](/platform/notifications). Reports produced by an individual Mjolnir run are downloaded from the run itself, not from this page. See [Mjolnir runs](/mjolnir/runs#downloading-reports). ## The report list Delivered pentest reports appear in a single table, newest first. Each row shows the pentest name (or the client name on a standalone report), the revision number, the date the report was last updated, and whether the PDF is **Ready** or still **Pending**. Select rows with the checkbox in the first column, or right-click a row to download the PDF, open it in a new tab, email a link, or copy the report name. Reports use an immutable revision system. When the content changes, say after a retest confirms a fix, Odin creates a new revision rather than editing the existing one. The row always points at the latest revision, and the downloaded file is named after the pentest and that revision, such as `Acme Q3 Pentest-rev3.pdf`. ## What is in a report The PDF opens with a cover page and a table of contents, followed by four parts. ### Executive summary * Confidentiality statement * Report overview, the narrative written by the testing team * Key findings, a compact table of the headline issues with their severities ### Findings * Vulnerability distribution, with counts by Critical, High, Medium, Low, and Info * Master findings table, listing the ID, title, state, and severity of every finding in the report * Detailed findings, each with the date it was identified (and resolved, where it has been), its type and CWE reference, severity, status, affected asset, description, business impact, supporting detail, and the suggested fix ### Appendices * Scope and methodology: the assets tested, their type, and the technology identified on each * Vulnerability coverage: the vulnerability classes the assessment explicitly checked for * Glossary ### Notices Legal notices covering tester qualifications, independence, and report authorisation. The wording differs between human-led engagements and autonomous Mjolnir engagements, and reports that carry no notices omit the section. ## Downloading a report Right-click a ready row and choose **Download report**, or press Enter on the focused row. Odin generates a short-lived signed link and saves the file straight to your machine. You can also select several rows and use **Download** in the selection bar. The list also supports keyboard navigation: j and k move focus, x toggles the checkbox, and Enter downloads the focused report. Odin reports page showing export options ## Emailing yourself a report **Send to email** opens a form where you pick a report and enter a recipient address. The recipient gets a link to the PDF that stops working 24 hours after it is sent, and the email states the expiry date. You can only send a report to **your own** email address, the one on your Odin account. Odin rejects any other recipient. To share a report outside Odin, download the PDF and send it yourself. Sending requires the Member role or above. The button stays disabled until at least one report has a PDF. ## Exporting the report list **Export** downloads the list itself rather than the PDFs, as CSV, Markdown, or JSON. Each row carries the report name, whether a PDF exists, the revision number, and the created and updated timestamps, which is enough to track deliverables in your own systems. # Roles & Permissions Source: https://docs.borghq.io/platform/roles-and-permissions Understand the four roles in Odin and what each one can do Odin uses a four-tier role hierarchy to control access within your organisation. Each role inherits the permissions of the roles below it, so a higher role can always do everything a lower role can. ## Role overview | Role | Description | Typical use | | ------------- | ----------------------------------------------------- | ---------------------------------- | | **Owner** | Full control over the organisation, including billing | Founders, security leads | | **Admin** | Manage members, settings, and all security data | Team managers, senior engineers | | **Member** | Day-to-day access to security data and pentests | Security analysts, developers | | **Read only** | View-only access to findings, reports, and assets | Stakeholders, auditors, executives | Owner and Admin have the same access to almost every part of the platform. The difference is who they can manage: an Admin cannot act on another Admin or on an Owner. ## Permissions matrix | Action | Read only | Member | Admin | Owner | | -------------------------------------------------------------- | :-------: | :----: | :---: | :---: | | View findings, assets, reports, pentests, and team members | ✓ | ✓ | ✓ | ✓ | | Export a list to CSV, Markdown, or JSON | ✓ | ✓ | ✓ | ✓ | | Post messages in a finding discussion | ✓ | ✓ | ✓ | ✓ | | Edit your own profile and sign-in methods | ✓ | ✓ | ✓ | ✓ | | Create, edit, and delete assets | | ✓ | ✓ | ✓ | | Update finding statuses, one at a time or in bulk | | ✓ | ✓ | ✓ | | Assign findings to teammates | | ✓ | ✓ | ✓ | | Request a retest | | ✓ | ✓ | ✓ | | Create issues in GitHub, GitLab, Jira, or Linear | | ✓ | ✓ | ✓ | | Email yourself a report link | | ✓ | ✓ | ✓ | | Connect and configure integrations | | ✓ | ✓ | ✓ | | Launch and cancel Mjolnir runs, manage suppression rules | | ✓ | ✓ | ✓ | | Change your own notification preferences | | ✓ | ✓ | ✓ | | Submit feedback | | ✓ | ✓ | ✓ | | Invite, edit, and remove team members | | | ✓ | ✓ | | Resend an invitation | | | ✓ | ✓ | | Manage billing, plans, payment methods, seats, and auto top-up | | | ✓ | ✓ | | Create and revoke API keys | | | ✓ | ✓ | | Configure single sign-on | | | ✓ | ✓ | | Manage verified domains | | | ✓ | ✓ | | Set the organisation's finding-ID prefix | | | ✓ | ✓ | | Set organisation-wide finding notification defaults | | | ✓ | ✓ | | Rename the organisation and set discussion email defaults | | | ✓ | ✓ | | Map Slack users to Odin accounts | | | ✓ | ✓ | | Change or remove an Admin | | | | ✓ | Your role is not the only thing that decides what you see. Which pages are switched on for your organisation is a separate setting, so two people holding the same role in different organisations can end up with different sidebars. ## Step-up verification A few actions ask you to confirm your identity again before they go through, even though you are already signed in: inviting, editing, or removing a team member, buying or releasing seats, changing the finding-ID prefix, changing organisation settings, and editing your own profile. See [Step-up verification](/platform/step-up-verification) for what the prompt looks like. ## Role details ### Owner Owners have unrestricted access. No one inside Odin can change an Owner's role or remove them, not even another Owner, so handing the role over means promoting the incoming person to Owner and then asking us to remove the outgoing one. **When to use:** the person ultimately responsible for the organisation's security programme, typically a founder, CISO, or security lead. Most organisations need only one or two Owners. An Owner cannot be demoted or removed from within Odin, so assign the role deliberately. If you need an Owner changed, contact [mail@borghq.io](mailto:mail@borghq.io). ### Admin Admins look after the organisation itself: who is in it, what it pays for, and how it is configured. **When to use:** team managers or senior engineers who need to invite people, manage seats and billing, or set up integrations, single sign-on, and API keys. **Cannot do:** * Change or remove another Admin, or any Owner * Promote anyone to Admin or Owner ### Member Members have full day-to-day access to security data. They manage assets, update finding statuses, create issues in connected trackers, email themselves reports, and launch scans. **When to use:** anyone actively working with security data, such as analysts triaging findings or engineers managing the attack surface. **Cannot do:** * Invite, edit, or remove team members * Change anyone's role * Reach billing, seats, API keys, single sign-on, or verified domains * Change organisation-wide settings ### Read only Read only users see everything the organisation has access to and can take part in finding discussions, but they cannot change any security data. **When to use:** people who need visibility without making changes, such as executives reviewing posture, auditors, or compliance officers. **Cannot do:** * Create, edit, or delete assets * Update finding statuses or assign findings * Create tracker issues or email report links * Manage integrations or scans * Anything under team, billing, or organisation settings Read only users can still edit their own profile and manage their own sign-in methods. ## Who can manage whom Managing another member, whether that means inviting them, changing their role, or removing them, requires the Admin or Owner role. Within that, you can only act on someone whose role sits strictly below your own, and you can only assign roles below your own: * **Owner** can manage Admins, Members, and Read only users * **Admin** can manage Members and Read only users * **Member** and **Read only** cannot manage anyone * No one can manage an Owner, and no one can change their own role This prevents privilege escalation: nobody can grant a role equal to or higher than their own. Learn how to invite members, change roles, and remove users # Step-up Verification Source: https://docs.borghq.io/platform/step-up-verification Re-authenticate before performing sensitive actions Step-up verification is an extra identity check that Odin requires before you can perform sensitive actions. Even though you're already signed in, you'll be asked to confirm your identity again to protect against session hijacking and unauthorised changes. ## How it works When you trigger a protected action, a verification dialog appears. You can confirm your identity using either method: * **Passkey**: if you have a passkey registered, this is the default. Tap your fingerprint sensor, use Face ID, or insert your security key. * **Email OTP**: a 6-digit code is sent to your email address. Enter it within 5 minutes. Once verified, the action proceeds. ## How long a verification lasts A verification lasts **5 minutes**, and Odin reuses it for the rest of that window. If you invite three people and then change someone's role, you verify once at the start instead of before each action. After 5 minutes the dialog comes back. Reloading the page clears the verification too, since Odin holds it in the browser tab rather than in your session. Registering a [passkey](/platform/profile#passkeys) makes step-up verification faster. Instead of waiting for an email code, you can verify with a single biometric prompt. ## What requires step-up verification | Action | Location | | ------------------------------------- | ---------------------------------------------------------------------------- | | Updating your name | [Profile](/platform/profile) | | Removing a passkey | [Profile](/platform/profile) | | Changing organisation settings | [Organisation Settings](/platform/organisation-settings) | | Changing the finding reference prefix | [Organisation Settings](/platform/organisation-settings#finding-identifiers) | | Inviting a team member | [Team Management](/platform/team-management) | | Changing a member's role | [Team Management](/platform/team-management) | | Removing a team member | [Team Management](/platform/team-management) | | Adding extra seats | [Billing](/platform/billing#seats) | | Releasing unused seats | [Billing](/platform/billing#seats) | Apart from the two Profile rows, every action here is admin-only, so members only meet the dialog on their own profile. One exception to the Team Management row: the invites you send from the welcome flow when you first set up your organisation don't ask you to verify. ## OTP verification When you trigger a protected action, the verification dialog opens and an OTP code is sent to your email automatically. Type the 6-digit code from your email. Verification happens automatically once all digits are entered. The protected action proceeds as normal. If the code doesn't arrive, click **Resend code** after the 60-second cooldown. Codes expire after 5 minutes. ## Passkey verification If you have a passkey registered, the dialog defaults to passkey verification. Follow your device's biometric or security key prompt to confirm your identity. You can switch between passkey and OTP verification at any time using the link at the bottom of the dialog. # Team Management Source: https://docs.borghq.io/platform/team-management Manage workspace members, roles, and permissions Team management is where Admins and Owners control who has access to the organisation, what role they have, and how to onboard new members. Open it from **Management > Team** in the sidebar. Everyone in the organisation can open the page and see the member list. Only Admins and Owners see the **Add user** button and the per-row actions menu. ## Roles Odin has four roles: **Owner**, **Admin**, **Member**, and **Read only**, each with a different level of access. See [Roles & Permissions](/platform/roles-and-permissions) for a full breakdown of what each role can do. Owners cannot be edited or removed from within Odin, by anyone. To change or remove an Owner, contact [mail@borghq.io](mailto:mail@borghq.io). ## Inviting members Go to **Management > Team** in the sidebar. The **Invite team members** dialog opens with one empty row. Add a row per person, up to 20 at a time, and pick a role for each one. The role list only offers roles below your own, so an Admin can invite Members and Read only users but not another Admin. The dialog rejects an email that appears twice in the same batch. Inviting requires [step-up verification](/platform/step-up-verification), so you are asked to confirm who you are before the invitations go out. Each person receives an email telling them who invited them, to which organisation, and with what role, plus a link to the Odin sign-in page. They appear in the team table straight away with an **Invited** badge. There is no separate acceptance step. The membership is created when you send the invitation, and the badge changes to a joined date the first time that person signs in. The dialog checks your seats before you send. If none are left, or you have added more rows than seats, it says so up front with a **Manage seats** link through to [Billing](/platform/billing) and disables sending until you remove rows or buy seats. If a seat is taken by someone else between opening the dialog and sending, it stops on the first blocked row; invitations already sent in that batch still stand. Inviting someone who is already in the organisation is rejected rather than duplicated. ## Searching and filtering Above the team table you can: * **Search** by name or email * **Filter** by role (Owner, Admin, Member, Read only) The table lists everyone matching your filters with their name, email, role, and the date they joined, shown as a relative time such as "3 months ago". People who have not signed in yet show an **Invited** badge in that column instead. Admins and Owners see an **Actions** column when they can manage at least one person on the page, with **Edit**, **Resend invite**, and **Remove**. The column is hidden when nobody on the page is below their role — for example an Owner looking only at their own row. You can move through the rows with the [list navigation keys](/platform/command-palette). For Admins and Owners, **Enter** opens the edit dialog for the highlighted member. ## Changing a role or name Click a member's row, or use the actions menu on the right and choose **Edit**, then change their role, first name, or last name. The row is only clickable for members you are allowed to manage. The rules the platform enforces: * Only Admins and Owners can edit anyone * You can only edit someone whose role is below your own, so an Admin cannot edit another Admin * You can only assign roles below your own * You cannot change your own role * Nobody can edit an Owner Everyone in the organisation gets a notification when a role changes. ## Removing a member Choose **Remove** from the member's actions menu, or from inside their edit dialog, then confirm. You cannot remove yourself, you cannot remove an Owner, and you can only remove someone whose role is below your own. Removal requires [step-up verification](/platform/step-up-verification). Removing someone frees their seat, and your subscription is updated to match the new member count. Right-click any row for the same actions as its menu, plus **Copy email**. ## Resending an invitation If someone has not signed in yet, open their actions menu and choose **Resend invite** to send the same email again. Once they have signed in at least once, resending is no longer available, since they already have access. ## Exporting the team list Use the **Export** dropdown next to **Add user** to download the current list as CSV, Markdown, or JSON. The export covers whatever the filters are currently showing and includes name, email, role, status, and joined date. Every role can use it, so a Read only auditor can pull an access list without help. # Browser Agents (WebMCP) Source: https://docs.borghq.io/platform/webmcp Let an AI agent built into your browser drive Odin on your behalf Odin publishes a small set of tools through [WebMCP](https://webmachinelearning.github.io/webmcp/), the web standard that lets an agent built into your browser discover what a page can do and act on it for you. When you open Odin in a supporting browser, an agent can look up findings, summarise your posture, move around the app, and, if you ask it to, update a finding's status, all inside your signed-in session. Nothing changes for browsers without WebMCP. Odin checks for the API before touching it and stays silent when it is missing. WebMCP is an early browser feature. As of Chrome 149 it is available through an origin trial, or locally by enabling `chrome://flags/#enable-webmcp-testing` and relaunching. Other browsers have not shipped it yet. ## How it works Tools run entirely in your browser tab and call the same Odin API the interface uses, with your existing session cookie. An agent can never see more than you can: every tool checks the same organisation gating as the sidebar, and status changes are only offered to Members, Admins and Owners. Odin also labels each tool for the agent: * **Read-only** tools never change anything. * **Consequential** tools, such as updating a finding's status, prompt the browser to confirm with you before they run. * **Untrusted content** tools return data produced by scanners or reconnaissance. Agents are told to treat that text as data rather than instructions, which limits prompt-injection risk. ## Available tools | Tool | What it does | | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `get_current_context` | Reports the active organisation, your role, the current page, and the pages your organisation can open | | `get_security_overview` | Finding counts by severity and status, asset counts, and current pentest engagements | | `open_page` | Navigates to a page in the sidebar, for example Findings or Assets | | `open_findings` | Opens the Findings list with severity, status, source, repository, or search filters applied, or opens one finding's detail view | | `open_asset` | Opens the detail panel for one asset | | `list_findings` | Lists findings with filters and paging, returning compact summaries | | `get_finding` | Fetches one finding by identifier such as `ODI-12`, with description, impact, and remediation excerpts | | `update_finding_status` | Moves a finding to Mitigating, Open for retest, or Acknowledged. Members and above only | | `list_assets` | Lists attack-surface assets with type, source, status, and search filters | Tools for pages your organisation cannot open are not registered at all, so the list an agent sees may be shorter than this one. ## Things to try * *"Which critical findings are still open?"* * *"Show me the findings for the `acme/web` repository."* * *"Summarise my security posture."* * *"Open ODI-12 and explain how to fix it."* * *"Mark ODI-12 as mitigating."* The browser asks you to confirm before the status changes. ## Privacy and limits * Tool calls are counted for product analytics by tool name only. Arguments and results are never sent. * Each response is capped at a few thousand characters. Ask the agent to add filters or page through results when a list is truncated. * A tool call times out after 30 seconds and reports the failure to the agent. * The tools are only exposed to Odin's own origin. Pages embedding Odin in a frame cannot reach them. For coding agents outside the browser, such as Cursor, use the [Odin MCP server](/platform/odin-mcp) with an API key instead.