Help Center

Step-by-step instructions for every IndexTracer feature — from your first asset discovery to webhook signature verification.

01

Getting Started

IndexTracer takes you from “I have a domain” to “I have a continuous security feedback loop” in about ten minutes. Here's the journey end to end so the rest of this page makes sense.

1. Create an account

Visit the signup page and provide an email address and a password. We send a verification email immediately. Click the link inside it to confirm the address — until you do that, you can log in but won't be able to launch scans, because the scanner requires a verified email to mitigate abuse.

After verification, you land on the Dashboard. A new tenant is created automatically for you (one tenant per user) with no Stripe customer attached — you only get a Stripe customer record the first time you start a paid plan.

2. Add an asset

Before scanning anything, you tell us what you own. Open Assets → New Asset and enter your root domain (for example example.com). You have two paths:

  • Manual single asset — for one host you already know about.
  • Discover subdomains — for the case where you want us to find every subdomain you own from Certificate Transparency logs and probe each one.

3. Verify ownership

Once an asset is in the system, it sits in the unverified state. You prove control via DNS TXT record or a .well-known file. Verification takes 1–5 minutes depending on DNS propagation. Only verified assets are scannable — this prevents anyone from accidentally (or maliciously) scanning a domain they don't own.

4. Scan or subscribe

Pick a verified asset and either kick off a one-shot scan (Scans → New Scan) or subscribe it to a recurring scan on hourly, daily, or weekly cadence. The first scan populates a baseline; subsequent scans produce diff events rather than re-flagging known issues.

5. Receive diffs

Configure a webhook URL or email digest to be notified the moment a new finding appears, an old finding closes, a severity changes, or your tech stack drifts. We sign webhooks with HMAC-SHA256 so you can verify they actually came from us.

02

Asset Discovery (ASM)

Modern attack surfaces leak. A team ships a new staging subdomain and forgets it. Marketing puts up a campaign microsite. A vendor proxies traffic through your wildcard cert. None of those show up in your asset inventory. Asset discovery solves that — it queries the same public Certificate Transparency logs that browsers use to validate HTTPS certs and surfaces every hostname your CA has ever signed.

How discovery works under the hood

  1. You submit a root domain (example.com) and we create a discovery job.
  2. The job queries crt.sh for all certificates issued for *.example.com in the past 90 days.
  3. We dedupe wildcard certs, expired hosts, and obvious throwaway names (localhost, IP literals, ACME challenge artifacts).
  4. Each remaining candidate is HTTP-probed: we record the final URL after redirects, status code, scheme, server header, page title, response time, and whether HTTPS is enforced.
  5. The asset list lands in the dashboard with status discovered and a probe snapshot. Failed probes get status unreachable.

Adding a discovery job

  1. Open Dashboard / Assets / New Asset.
  2. Choose the “Discover subdomains” tab.
  3. Enter your root domain — bare apex form, no scheme or path. Example: example.com, not https://www.example.com.
  4. Click Start Discovery.
  5. The page redirects to Assets / Discovery Jobs / [id] which polls progress every 3 seconds. Discovery typically completes in 30–90 seconds.

Asset statuses

  • pending — just inserted, waiting for the discovery worker.
  • discovered — found in CT logs but not yet HTTP-probed.
  • probed — HTTP probe complete, metadata captured.
  • unverified — ready for ownership verification (this is the default after a manual add).
  • verified — ownership confirmed. Scannable.
  • unreachable — HTTP probe failed (DNS miss, connection refused, TLS error).
  • archived — manually retired by you. Hidden from default views.

Filtering and sorting

The asset list supports filters by status and asset type, plus search by hostname. The status filter is sticky in your browser's local storage so your preferred view persists across visits.

03

Ownership Verification

Verification is mandatory before scanning. We support two methods — pick whichever is easier for you to control. Both produce the same end state (verified) and both can be re-run if a token expires or you want to re-confirm.

Method 1: DNS TXT record (recommended)

Best for production domains where you control DNS. Survives application redeploys and proves you own the domain itself, not just one server.

  1. Open the asset detail page (Assets / [hostname]).
  2. Find the Verification panel — it shows your unique token, something like indextracer-verify=8f3a2b9c4d1e5....
  3. Copy the token to your clipboard with the copy button.
  4. Log in to your DNS provider and create a new TXT record:
Type:  TXT
Host:  @            (or the apex / blank — depends on provider UI)
Value: indextracer-verify=8f3a2b9c4d1e5...
TTL:   300          (5 minutes — speeds up re-verification)
  1. Save the record. Wait for DNS propagation — typically 1–5 minutes with TTL=300, longer if your provider caches aggressively.
  2. Back in the asset page, click the “Verify Now” button. We do a fresh DNS lookup against multiple resolvers and accept the asset the moment one of them sees the correct token.

Provider-specific tips

  • Cloudflare: DNS → Records → Add Record → TXT. Set Proxy status to “DNS only”. The Name field accepts @ for the apex.
  • Route 53: Hosted zones → your zone → Create record → Record type TXT. Leave Record name blank for the apex. Quote the value with double quotes if your console doesn't do it automatically.
  • GoDaddy: My Products → DNS → Add → TXT. Use @ in the Host field.
  • Namecheap: Domain List → Manage → Advanced DNS → Add New Record → TXT Record. Host = @.

Method 2: .well-known file

Best when you can deploy a static file faster than you can edit DNS — useful for CI-managed assets and short-lived staging environments.

  1. On the asset detail page, switch the Verification panel to the .well-known tab and copy the token.
  2. Create a file at this exact path on the asset:
https://your-asset.example.com/.well-known/indextracer-verify.txt

File contents (one line, no trailing newline):
indextracer-verify=8f3a2b9c4d1e5...
  1. The file must be served with HTTP 200 status and a plain text content type (text/plain or no content type set).
  2. No redirects. If your server redirects /.well-known/… to HTTPS or to a www subdomain, the verifier will follow at most one redirect on the same host. Cross-host redirects fail verification.
  3. Click “Verify Now”.

Re-verification and token rotation

Each verification token is unique per asset and never expires. You can rotate the token from the asset page if you suspect the old one was leaked. After rotation the asset moves back to unverified until you republish the new TXT record or file.

Common verification failures

  • DNS lookup returned no TXT records — either the record hasn't propagated yet (trydig TXT example.com +short from your terminal to confirm), or you added it on a different apex (e.g. www.example.com instead of example.com).
  • Wrong token in TXT — tokens are asset-specific. Double-check you copied the token from the right asset page.
  • 404 on .well-known — some Next.js / Nuxt apps return 404 for unknown paths. Add an explicit static file in public/.well-known/or configure your server to serve the file directly.
  • Content-type mismatch — if your framework returns the file with text/html, our verifier still accepts it as long as the body matches the token exactly. But many CDNs strip or rewrite the body for HTML content — serve it as plain text to avoid this.

04

Running Scans

Every scan runs an autonomous agent loop: a Playwright crawler maps the attack surface, an offensive Claude agent generates context-aware payloads, and a Gemini-powered analyst assesses responses for evidence of vulnerability. Scans typically take 5–30 minutes depending on surface size.

Two ways to start a scan

From a verified asset (recommended)

  1. Assets / [hostname] / Launch Scan
  2. The target URL is auto-populated from the asset's probed URL. You only need to choose configuration options.

From a raw URL

  1. Scans / New Scan
  2. Type or paste the target URL. The URL must be HTTPS in production unless you explicitly allow HTTP via the config.
  3. The hostname must already be a verified asset under your tenant — if it isn't, the form prompts you to add it first.

Scan configuration

  • Target URL — the entry point. The crawler discovers other endpoints from here.
  • Scopesingle_page (only the entry point), same_path_prefix (anything under /api/v1/ if that's your entry path), or same_host (full spider).
  • Max depth — how many link levels to follow from the entry point. Default 3.
  • Max requests — hard cap on requests per scan. Defaults to 200, max 5000.
  • Dry run — when enabled, the scanner discovers and analyzes endpoints but does not fire active exploit payloads. Use this to map a target without sending anything attacker-shaped.
  • Authentication — see below.

Authenticated scanning

To scan endpoints behind login, attach credentials to the scan config. We support four mechanisms:

Bearer token

{
  "auth": {
    "type": "bearer",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp..."
  }
}

Sent as Authorization: Bearer <token> on every request. Good for stateless JWT-based APIs.

Cookie session

{
  "auth": {
    "type": "cookie",
    "cookies": {
      "session": "abc123def456",
      "csrf_token": "..."
    }
  }
}

All cookies are attached on every request. Useful for classic server-rendered apps with session cookies.

Basic auth

{
  "auth": {
    "type": "basic",
    "username": "scanner",
    "password": "..."
  }
}

Custom headers

{
  "auth": {
    "type": "headers",
    "headers": {
      "X-Api-Key": "...",
      "X-Tenant-Id": "..."
    }
  }
}

Watching scans live

Open Scans / [id] and the page subscribes to a WebSocket feed that streams agent reasoning, discovered endpoints, OWASP-categorized findings, and exploit chains in real time. The feed reconnects automatically if your network blips.

Reading scan results

When a scan completes, the report shows:

  • Summary — severity counts and OWASP Top 10 distribution as a horizontal bar chart.
  • Findings — one row per finding with severity badge (Critical / High / Medium / Low / Info), OWASP category (e.g. A03:2021 Injection), title, target URL, and CVE references where applicable.
  • Evidence — click any finding to expand the request/response pair, the payload that triggered detection, and the analyst's reasoning.
  • Exploit chains — multiple findings combined into a single attack path with composite CVSS score.
  • Remediation — per-finding suggested fix, mapped to the OWASP cheat sheet for the relevant category.

05

Continuous Monitoring (Subscriptions)

A subscription is a recurring scan attached to a verified asset. The scheduler wakes every two minutes, queries for any subscription whose next_scan_at is in the past, and fires off a scan bound to that subscription. Each scan's findings are diffed against the previous scan's — you receive notifications about changes, not raw results.

Creating a subscription

  1. Pick a verified asset: Assets / [hostname].
  2. Click “Subscribe to monitoring”.
  3. Choose interval: hourly, daily, or weekly. Daily is the default and the sweet spot for most production assets.
  4. Configure notification channels (see the Notifications section). You can add channels later, but starting with at least one means you actually get the value out of monitoring.
  5. Click Subscribe. Your first monitored scan starts immediately to establish a baseline. Future scans run on your chosen cadence.

How the scheduler picks scans

The scheduler runs on every API machine, but only one machine actually executes scans at a time — we use Redis-backed leader election with a 90-second lock refreshed every 60 seconds. If the leader machine crashes, another takes over within 90 seconds without duplicating scans.

Pausing, resuming, cancelling

  • Pause — the subscription stays around but stops firing scans until you resume. Useful during planned maintenance windows.
  • Resume — the next scan fires at the next regular interval boundary, not immediately.
  • Cancel — tears down the subscription permanently. Existing scan results and diff events stay in the database for your records.

Failure handling

If a monitored scan fails (target unreachable, our scanner errored), the subscription's consecutive_failures counter increments. After five consecutive failures the subscription auto-pauses and you receive a notification on whatever channels you have configured. This stops a permanently broken target from burning your scan budget while we wait for you to look at it.

06

Diff Events

Every monitored scan compares its findings against the previous scan using a stable SHA-256 signature derived from the OWASP category, target URL pattern, and payload shape (we deliberately exclude scan-specific noise like timestamps and request IDs). The diff produces four event types:

finding_new

A vulnerability that wasn't on the previous scan. The most actionable signal — a regression, a freshly-exposed endpoint, or a new dependency CVE.

finding_closed

A previously-flagged issue is gone. Evidence your fix landed in production — confirm before you close the ticket.

severity_changed

Same finding, different impact. The upstream library got patched, the asset became reachable, or the exploit chain got longer.

tech_drift

New framework, server, or runtime detected. Either your team shipped something new, or someone else is running on your subdomain.

Reading diff events in the dashboard

Open Assets / [hostname] and the Activity tab shows a chronological feed of diff events for that asset. Filter by event type, severity, or time range. Each event links back to the scan that produced it for full context.

Why diffs instead of raw findings?

If you scan daily, you generate a lot of duplicate findings — the same XSS that was there yesterday is there today. Pushing those duplicates as alerts produces alert fatigue and trains your team to ignore notifications. Diffs only fire when something actually changed, which matches the cadence of real incident-worthy events.

07

Notifications

Each subscription has a notification_config object. We currently support two channels — webhook and email — and you can enable both on the same subscription.

Webhook delivery

Best for piping diffs into Slack, PagerDuty, your internal SIEM, or a custom queue. Add the URL when creating or editing a subscription.

Payload shape

Each event is delivered as an HTTP POST with a JSON body:

POST https://your-webhook.example.com/indextracer
Content-Type: application/json
X-IndexTracer-Signature: v1=hex(hmac_sha256(secret, body))
X-IndexTracer-Timestamp: 1714780800
X-IndexTracer-Event-Id: 0193f7c8-9ab2-7541-b7b3-fb3a91c1cb22
User-Agent: IndexTracer-Webhook/1.0

{
  "id": "0193f7c8-9ab2-7541-b7b3-fb3a91c1cb22",
  "tenant_id": "1d8f7a2b-...",
  "asset_id": "ab3c5d2e-...",
  "subscription_id": "7e1a4f9b-...",
  "scan_id": "f0a2c4e6-...",
  "previous_scan_id": "9d1b3c5d-...",
  "event_type": "finding_new",
  "created_at": "2026-05-03T18:00:00.123Z",
  "finding": {
    "title": "SQL Injection in /api/users?id=",
    "severity": "critical",
    "owasp_id": "A03:2021",
    "target_url": "https://api.example.com/api/users?id=",
    "evidence_url": "https://app.indextracer.com/scans/.../findings/..."
  }
}

Verifying the HMAC signature

Every webhook is signed with HMAC-SHA256 over the raw request body using a shared secret unique to the subscription. The secret is shown once when the subscription is created — copy it into your receiver's configuration. Verify before trusting the body.

Node.js (Express):

import crypto from "node:crypto";
import express from "express";

const app = express();
const SECRET = process.env.INDEXTRACER_WEBHOOK_SECRET;
const MAX_SKEW_SECONDS = 300; // 5 minutes

app.post(
  "/indextracer",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const sig = req.header("X-IndexTracer-Signature") || "";
    const ts = parseInt(req.header("X-IndexTracer-Timestamp") || "0", 10);
    const expected = "v1=" + crypto
      .createHmac("sha256", SECRET)
      .update(req.body)
      .digest("hex");

    // Constant-time comparison + replay window check.
    const sigOk =
      sig.length === expected.length &&
      crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
    const fresh = Math.abs(Date.now() / 1000 - ts) < MAX_SKEW_SECONDS;

    if (!sigOk || !fresh) return res.status(401).end();

    const event = JSON.parse(req.body.toString("utf8"));
    handleEvent(event);
    res.status(204).end();
  }
);

Python (FastAPI):

import hmac, hashlib, time, os
from fastapi import FastAPI, Request, Header, HTTPException

app = FastAPI()
SECRET = os.environ["INDEXTRACER_WEBHOOK_SECRET"].encode()
MAX_SKEW = 300  # seconds

@app.post("/indextracer")
async def receive(
    request: Request,
    x_indextracer_signature: str = Header(...),
    x_indextracer_timestamp: int = Header(...),
):
    body = await request.body()
    expected = "v1=" + hmac.new(SECRET, body, hashlib.sha256).hexdigest()

    if not hmac.compare_digest(x_indextracer_signature, expected):
        raise HTTPException(401, "bad signature")
    if abs(time.time() - x_indextracer_timestamp) > MAX_SKEW:
        raise HTTPException(401, "stale timestamp")

    event = await request.json()
    handle_event(event)
    return {"ok": True}

Retries and the delivery log

Every delivery attempt is recorded in our notification_deliveries table with status, HTTP response code, attempt count, and error message. We retry failed deliveries with exponential backoff (1s, 5s, 30s, 5m, 30m, 4h) up to six times. After the sixth failure the delivery is marked failed and surfaces in the dashboard for manual investigation.

Your endpoint must respond with 2xx within 10 seconds to count as successful. Slow responses are treated as failures and retried — consider queueing the work asynchronously inside your handler.

Email delivery

Best for individual humans who want a digest. Add a recipient address to notification_config.email on the subscription.

Emails are batched into digests rather than fired per-event — you get one summary email per scan containing all the diff events from that scan, plus a deep link back to the dashboard for details. Empty diffs (no changes) don't produce email by default; toggle “Send empty digests” on the subscription if you want a daily “all clear” receipt.

08

Billing & Plans

IndexTracer is free to try with no credit card. Paid features — principally continuous monitoring subscriptions — are metered through Stripe.

Free plan

  • Unlimited one-shot scans on verified assets.
  • Asset discovery up to 5 root domains.
  • Up to 1 active monitoring subscription.
  • Webhook + email notifications included.

Active plan (metered)

Once you create your second monitoring subscription, we prompt you to add a payment method via Stripe Checkout. Subscriptions then bill per-scan against a Stripe metered price — you only pay for scans that actually run. Pausing a subscription stops billing immediately.

The current usage meter is visible in the dashboard header at all times. The bar shows scans this month vs your plan's included quota.

Updating billing details

Dashboard / Billing opens the Stripe Customer Portal in a new tab. You can update payment methods, download invoices, change billing address, or cancel there — all without involving us.

Cancellation

Cancel from the Stripe Customer Portal. Cancellation takes effect at the end of your current billing period; monitoring subscriptions auto-pause at that point. Your scan history and diff events stay in the database indefinitely so you can re-subscribe later without losing context.

09

Account Settings

Email and password

Dashboard / Settings. Email changes require re-verification of the new address — we send a confirmation link to the new email and the change only takes effect after you click it. Password changes take effect immediately and revoke all other sessions.

Sessions and sign-out

Sign out from the sidebar. This invalidates your current Supabase session token. To force-revoke all sessions (e.g. if you suspect a token leak), change your password — that does it implicitly.

Tenant settings

Each user has exactly one tenant in the current product. All your assets, scans, subscriptions, and diff events live under that tenant and are isolated from other tenants via row-level security in Postgres — even if a query at the database level were to bypass our application code, RLS would still prevent cross-tenant reads.

Admin features

Admin users (typically only the workspace owner) see an Admin link in the sidebar. From Admin you can view all tenants, scan activity across the platform, and an audit log of admin actions. Admin actions require step-up re-authentication for sensitive operations.

10

Troubleshooting

“Internal server error” when starting a scan

Usually means our background queue can't reach Redis. We monitor this and typically resolve in minutes. Refresh and retry; if it persists for more than 10 minutes, file a support ticket and we'll dig in.

Scan completes but reports zero findings

Two common causes:

  • Dry-run mode is on. Dry-run discovers endpoints but never fires payloads, so it can't detect injection-class issues. Disable dry-run on the next scan.
  • The crawler couldn't reach anything. Check the live feed — if you see only the entry point and nothing else, the target is likely behind auth and you need to attach credentials.

Webhook receiver isn't getting events

  1. Check Subscription / Delivery Log — if attempts show failed with HTTP 4xx or timeout, your endpoint is the culprit.
  2. If attempts show sent but you don't see them on your side, check that your receiver isn't silently dropping unsigned/invalid bodies — verify the HMAC step.
  3. Test against webhook.site to confirm we're actually sending. Switch the URL on the subscription temporarily, fire a test scan, inspect the request, then switch back.

Email digest isn't arriving

  • Check spam — first emails from a new sender domain often land there.
  • Confirm the recipient address on the subscription is correct.
  • Empty digests are suppressed by default. Toggle “Send empty digests” on the subscription if you want confirmation that nothing changed.

DNS verification keeps timing out

Some providers (notably Squarespace and certain GoDaddy setups) cache TXT records for hours regardless of TTL. Use dnschecker.org to confirm the record is visible globally before retrying. If dig TXT example.com +short from your own machine returns the token but our verifier doesn't see it, try the .well-known method instead — it bypasses DNS entirely.

Where to find logs

Per-scan logs live on the scan detail page (live feed + archived after completion). Account-level audit logs are available to admins under Admin / Activity. We don't expose application server logs through the UI — if you need those for a support investigation, reference the scan ID in your ticket and we'll pull them.

11

Frequently Asked

Is it safe to scan production?

Yes. All payloads are observation-based — we inject inputs and watch responses without modifying target data. Built-in safety controls block destructive payloads (DROP TABLE, rm -rf, format string disasters). For extra-cautious environments, run a dry-run first to map endpoints, then a live scan.

What does the agent know about my code?

Nothing. We test the running application from outside, the same way an external attacker would. We have no source code access and ship no code. The analyst reasoning you see is generated from request/response pairs, not from inspecting your repo.

Can I scan APIs that aren't web apps?

Yes — REST and GraphQL APIs work natively. For GraphQL, point us at the /graphql endpoint; we introspect the schema and generate context-aware queries. For non-HTTP protocols (gRPC, WebSocket, custom binary), we don't currently have native support.

Can I scan IPs instead of hostnames?

Yes for hostnames you've verified ownership for. The hostname must resolve to the IP and the IP must be a routable public address — we block private and reserved ranges to prevent SSRF-style abuse of the scanner.

How are findings deduplicated across scans?

Each finding gets a stable signature derived from OWASP category, normalised target URL, and payload shape. The signature is what powers diff events — two scans finding the same issue produce the same signature and therefore don't emit a finding_new event the second time.

Where is my data stored?

Postgres on Supabase (US East). Scan-time secrets like bearer tokens are encrypted at rest with a per-tenant key. Findings are kept indefinitely for diff comparison; you can request deletion via support.

Can the agent be jailbroken via prompt injection in the target?

We harden against indirect prompt injection in two layers: the analyst prompt explicitly enumerates attacker-controlled fields and instructs the model to treat them as data, and we run an output validator that rejects responses containing instruction-shaped tokens (“ignore previous”, “disregard”, etc.). We track this as part of our agentic AI security posture.

Ready to start?

Free to try, no credit card required, unlimited scans on the free plan.