inspect

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 25, 2026 License: MIT Imports: 28 Imported by: 0

README

Inspect

Live website auditor for accessibility, TLS, cookies, and security headers

Go License CI


What is inspect

inspect is a Go library that crawls live websites and audits the pages it finds — broken links, security headers, forms, accessibility, performance, SEO, TLS, cookies, mixed content, subresource integrity, AI-readiness, and reachability. It is part of the hawk ecosystem: hawk wires inspect into its own commands, and inspect also ships an MCP server so any MCP-compatible agent can run audits.

inspect is a Go library (and MCP server), not a CLI. It ships no inspect binary of its own — it analyzes running URLs, not source code. Import it directly to embed website auditing in your own Go program, or run the MCP server to expose it to an agent.

It crawls concurrently (with rate limiting, robots.txt support, redirect handling, and SSRF protection), runs each check against the discovered pages, and returns findings with severity levels. Results can be emitted as SARIF for the GitHub Security tab.

Ecosystem Boundaries

Inspect is a Hawk support engine. Keep the dependency edge one-way:

  • use hawk-core-contracts for any cross-repo shared contracts (severity/finding vocabulary)
  • do not import hawk/internal/*
  • do not import removed legacy path hawk/shared/types; use hawk-core-contracts/types
  • do not import other engines (eyrie, yaad, tok, trace, sight) — engines are peers, not dependencies

Quick Start

import (
    "context"
    "fmt"

    "github.com/GrayCodeAI/inspect"
)

// One-shot scan with the Standard preset.
report, err := inspect.Scan(ctx, "https://example.com", inspect.Standard)
if err != nil {
    // handle error
}
for _, f := range report.Findings {
    fmt.Printf("[%s] %s: %s\n", f.Severity, f.URL, f.Message)
}

Requires Go 1.26+.

For repeated or high-throughput scans, reuse a Scanner (safe for concurrent use):

scanner := inspect.NewScanner(inspect.Standard, inspect.WithDepth(3))
r1, _ := scanner.Scan(ctx, "https://site-a.com")
r2, _ := scanner.Scan(ctx, "https://site-b.com")

Features

inspect ships nine built-in checks (registered in check.DefaultRegistry). The six marked (default) run in the Standard, Deep, and CI presets; the remaining three are opt-in via WithChecks.

  • Links (default) — crawls and reports broken/unreachable links
  • Security headers (default) — detects missing CSP, HSTS, and related headers; also audits TLS certificate validity/expiry, cookie Secure / HttpOnly / SameSite flags, and mixed content on HTTPS pages
  • Forms (default) — form validation checks (CSRF, action URLs)
  • Accessibility (a11y) (default) — meta/ARIA checks; optional axe-core and color-contrast analysis through the browser sub-module (headless Chromium via rod)
  • Performance (perf) (default) — resource sizes and render-blocking resources
  • SEO (default) — meta tags, structured data, and metadata checks
  • SRI — Subresource Integrity validation
  • AI-ready (aiready) — checks for agent/LLM-friendly metadata
  • Reachability — host/URL reachability checks
  • Concurrent crawler — depth limits, rate limiting, robots.txt, redirect following, and SSRF protection (private IPs blocked by default)
  • SARIF outputinspect.GenerateSARIF emits SARIF 2.1.0 for the GitHub Security tab
  • MCP server — expose inspect_scan and inspect_scan_dir to any agent
  • Extensible — register custom Checker implementations or declarative RuleCheck patterns

Presets

The default checks are: links, security, forms, a11y, perf, seo. Add the opt-in checks (sri, aiready, reachability) with WithChecks.

Preset Behavior
Quick Shallow crawl (depth 2), links only
Standard Balanced crawl (depth 5), the six default checks
Deep Exhaustive crawl (no depth limit), the six default checks
SecurityOnly Security-related checks only
CI Default checks, fail on high severity

MCP Server

inspect ships an MCP server (stdio transport) that exposes website auditing to any MCP-compatible agent:

import inspectmcp "github.com/GrayCodeAI/inspect/mcp"

srv := inspectmcp.New(inspect.Standard)
if err := srv.ServeStdio(); err != nil {
    // handle error
}

Tools:

  • inspect_scan — crawl a URL and run the configured checks
  • inspect_scan_dir — serve and scan a local directory of HTML files

Browser-Rendered Analysis

By default inspect analyzes raw HTTP responses. To analyze JavaScript-rendered pages and run axe-core accessibility checks, supply a BrowserEngine from the browser sub-module:

import "github.com/GrayCodeAI/inspect/browser"

engine, err := browser.New()
if err != nil {
    // handle error
}
defer engine.Close()

report, err := inspect.Scan(ctx, "https://example.com",
    inspect.Standard,
    inspect.WithBrowser(engine),
)

Custom Checks

// Declarative rule — no Go code beyond the struct.
inspect.RegisterRule(inspect.RuleCheck{
    RuleName:      "x-frame-options",
    RuleSeverity:  inspect.SeverityHigh,
    HeaderMissing: []string{"X-Frame-Options"},
})

// Full Checker implementation, scoped to a single Scanner.
scanner := inspect.NewScanner(inspect.WithCustomChecks(myCheck))

Examples

See the examples/ directory for runnable code samples.

Architecture

See docs/architecture.md for the package layout and data flow.

Ecosystem

inspect is part of the hawk ecosystem:

Component Repository Purpose
hawk GrayCodeAI/hawk AI coding agent
eyrie GrayCodeAI/eyrie LLM provider runtime
yaad GrayCodeAI/yaad Graph-based memory
inspect This repo Website audit library + MCP server

Contributing

Contributions are welcome — please read CONTRIBUTING.md before opening a pull request.

License

MIT - see LICENSE for details.

Documentation

Overview

Package inspect crawls websites and detects broken links, security issues, form problems, accessibility violations, and performance concerns.

It is designed as a standalone library imported by hawk — it has no CLI, no LLM dependency, and no TUI. Hawk wires inspect into its own commands.

Usage:

report, err := inspect.Scan(ctx, "https://example.com", inspect.Standard)
for _, f := range report.Findings {
    fmt.Printf("[%s] %s: %s\n", f.Severity, f.URL, f.Message)
}

For high-throughput or repeated scans, use the reusable Scanner:

scanner := inspect.NewScanner(inspect.Standard)
r1, _ := scanner.Scan(ctx, "https://site-a.com")
r2, _ := scanner.Scan(ctx, "https://site-b.com")

Package inspect version metadata.

The Version variable is sourced at compile time from the VERSION file at the repo root — the single source of truth used by release tooling (release-please, goreleaser), and CI.

Index

Constants

View Source
const ArchiveVersion = "1.0"

ArchiveVersion is the current archive format version.

Variables

View Source
var KnownVulnerabilities = map[string][]VulnEntry{

	"golang.org/x/crypto": {
		{CVE: "CVE-2022-27191", Severity: SeverityHigh, Description: "Denial of service via crafted Signer", AffectedVersions: []string{"0.0.0-2022"}, FixedVersion: "0.0.0-20220315160706"},
	},
	"golang.org/x/net": {
		{CVE: "CVE-2022-41723", Severity: SeverityHigh, Description: "HTTP/2 HPACK decoder denial of service", AffectedVersions: []string{"0.0.0-2022", "0.1", "0.2", "0.3", "0.4", "0.5", "0.6"}, FixedVersion: "0.7.0"},
		{CVE: "CVE-2023-44487", Severity: SeverityCritical, Description: "HTTP/2 rapid reset attack", AffectedVersions: []string{"0.0", "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "0.10", "0.11", "0.12", "0.13", "0.14", "0.15", "0.16"}, FixedVersion: "0.17.0"},
	},
	"golang.org/x/text": {
		{CVE: "CVE-2022-32149", Severity: SeverityHigh, Description: "Denial of service via crafted Accept-Language header", AffectedVersions: []string{"0.0", "0.1", "0.2", "0.3"}, FixedVersion: "0.3.8"},
	},
	"github.com/gin-gonic/gin": {
		{CVE: "CVE-2023-26125", Severity: SeverityHigh, Description: "Improper input validation allows path traversal", AffectedVersions: []string{"1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9.0"}, FixedVersion: "1.9.1"},
	},
	"github.com/dgrijalva/jwt-go": {
		{CVE: "CVE-2020-26160", Severity: SeverityHigh, Description: "Audience validation bypass", AffectedVersions: []string{"1", "2", "3"}, FixedVersion: "4.0.0 (use github.com/golang-jwt/jwt)"},
	},
	"github.com/tidwall/gjson": {
		{CVE: "CVE-2021-42248", Severity: SeverityHigh, Description: "Denial of service via crafted JSON", AffectedVersions: []string{"1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9.0", "1.9.1", "1.9.2"}, FixedVersion: "1.9.3"},
	},

	"lodash": {
		{CVE: "CVE-2021-23337", Severity: SeverityCritical, Description: "Command injection via template function", AffectedVersions: []string{"0.", "1.", "2.", "3.", "4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", "4.10", "4.11", "4.12", "4.13", "4.14", "4.15", "4.16", "4.17.0", "4.17.1", "4.17.2", "4.17.3", "4.17.4", "4.17.5", "4.17.6", "4.17.7", "4.17.8", "4.17.9", "4.17.10", "4.17.11", "4.17.12", "4.17.13", "4.17.14", "4.17.15", "4.17.16", "4.17.17", "4.17.18", "4.17.19", "4.17.20"}, FixedVersion: "4.17.21"},
		{CVE: "CVE-2020-8203", Severity: SeverityHigh, Description: "Prototype pollution in zipObjectDeep", AffectedVersions: []string{"0.", "1.", "2.", "3.", "4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", "4.10", "4.11", "4.12", "4.13", "4.14", "4.15", "4.16", "4.17.0", "4.17.1", "4.17.2", "4.17.3", "4.17.4", "4.17.5", "4.17.6", "4.17.7", "4.17.8", "4.17.9", "4.17.10", "4.17.11", "4.17.12", "4.17.13", "4.17.14", "4.17.15"}, FixedVersion: "4.17.16"},
	},
	"minimist": {
		{CVE: "CVE-2021-44906", Severity: SeverityCritical, Description: "Prototype pollution", AffectedVersions: []string{"0.", "1.0", "1.1", "1.2.0", "1.2.1", "1.2.2", "1.2.3", "1.2.4", "1.2.5"}, FixedVersion: "1.2.6"},
	},
	"node-forge": {
		{CVE: "CVE-2022-24771", Severity: SeverityHigh, Description: "Signature verification bypass with RSA PKCS#1 v1.5", AffectedVersions: []string{"0.", "1.0", "1.1", "1.2"}, FixedVersion: "1.3.0"},
	},
	"jsonwebtoken": {
		{CVE: "CVE-2022-23529", Severity: SeverityCritical, Description: "Insecure implementation of key retrieval function", AffectedVersions: []string{"0.", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5.0"}, FixedVersion: "8.5.1"},
	},
	"express": {
		{CVE: "CVE-2024-29041", Severity: SeverityMedium, Description: "Open redirect via malicious URL", AffectedVersions: []string{"0.", "1.", "2.", "3.", "4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", "4.10", "4.11", "4.12", "4.13", "4.14", "4.15", "4.16", "4.17", "4.18"}, FixedVersion: "4.19.2"},
	},
	"axios": {
		{CVE: "CVE-2023-45857", Severity: SeverityHigh, Description: "CSRF token exposure via cross-site requests", AffectedVersions: []string{"0.", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5"}, FixedVersion: "1.6.0"},
	},
	"semver": {
		{CVE: "CVE-2022-25883", Severity: SeverityMedium, Description: "Regular expression denial of service", AffectedVersions: []string{"5.", "6.0", "6.1", "6.2", "6.3.0"}, FixedVersion: "6.3.1"},
	},
	"tar": {
		{CVE: "CVE-2021-37701", Severity: SeverityHigh, Description: "Arbitrary file creation/overwrite via symlink", AffectedVersions: []string{"0.", "1.", "2.", "3.", "4.0", "4.1", "4.2", "4.3", "4.4.0", "4.4.1", "4.4.2", "4.4.3", "4.4.4", "4.4.5", "4.4.6", "4.4.7", "4.4.8", "4.4.9", "4.4.10", "4.4.11", "4.4.12"}, FixedVersion: "4.4.13"},
	},
	"glob-parent": {
		{CVE: "CVE-2020-28469", Severity: SeverityHigh, Description: "Regular expression denial of service", AffectedVersions: []string{"0.", "1.", "2.", "3.", "4.", "5.0", "5.1.0"}, FixedVersion: "5.1.2"},
	},
	"postcss": {
		{CVE: "CVE-2023-44270", Severity: SeverityMedium, Description: "Line return parsing error", AffectedVersions: []string{"0.", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.0", "8.1", "8.2", "8.3", "8.4.0", "8.4.1", "8.4.2", "8.4.3", "8.4.4", "8.4.5", "8.4.6", "8.4.7", "8.4.8", "8.4.9", "8.4.10", "8.4.11", "8.4.12", "8.4.13", "8.4.14", "8.4.15", "8.4.16", "8.4.17", "8.4.18", "8.4.19", "8.4.20", "8.4.21", "8.4.22", "8.4.23", "8.4.24", "8.4.25", "8.4.26", "8.4.27", "8.4.28", "8.4.29", "8.4.30"}, FixedVersion: "8.4.31"},
	},
	"ua-parser-js": {
		{CVE: "CVE-2022-25927", Severity: SeverityHigh, Description: "ReDoS vulnerability", AffectedVersions: []string{"0.7.0", "0.7.1", "0.7.2", "0.7.3", "0.7.4", "0.7.5", "0.7.6", "0.7.7", "0.7.8", "0.7.9", "0.7.10", "0.7.11", "0.7.12", "0.7.13", "0.7.14", "0.7.15", "0.7.16", "0.7.17", "0.7.18", "0.7.19", "0.7.20", "0.7.21", "0.7.22", "0.7.23", "0.7.24", "0.7.25", "0.7.26", "0.7.27", "0.7.28", "0.7.29", "0.7.30", "0.7.31", "0.7.32"}, FixedVersion: "0.7.33"},
	},

	"django": {
		{CVE: "CVE-2023-36053", Severity: SeverityHigh, Description: "Potential ReDoS in EmailValidator/URLValidator", AffectedVersions: []string{"0.", "1.", "2.", "3.0", "3.1", "3.2.0", "3.2.1", "3.2.2", "3.2.3", "3.2.4", "3.2.5", "3.2.6", "3.2.7", "3.2.8", "3.2.9", "3.2.10", "3.2.11", "3.2.12", "3.2.13", "3.2.14", "3.2.15", "3.2.16", "3.2.17", "3.2.18", "3.2.19"}, FixedVersion: "3.2.20"},
	},
	"flask": {
		{CVE: "CVE-2023-30861", Severity: SeverityHigh, Description: "Cookie exposure on cross-origin redirects", AffectedVersions: []string{"0.", "1.", "2.0", "2.1", "2.2.0", "2.2.1", "2.2.2", "2.2.3", "2.2.4"}, FixedVersion: "2.2.5"},
	},
	"requests": {
		{CVE: "CVE-2023-32681", Severity: SeverityMedium, Description: "Leaking Proxy-Authorization header to destination server", AffectedVersions: []string{"0.", "1.", "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14", "2.15", "2.16", "2.17", "2.18", "2.19", "2.20", "2.21", "2.22", "2.23", "2.24", "2.25", "2.26", "2.27", "2.28", "2.29", "2.30"}, FixedVersion: "2.31.0"},
	},
	"pillow": {
		{CVE: "CVE-2023-44271", Severity: SeverityHigh, Description: "Denial of service via uncontrolled resource consumption", AffectedVersions: []string{"0.", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.0"}, FixedVersion: "10.1.0"},
	},
	"urllib3": {
		{CVE: "CVE-2023-45803", Severity: SeverityMedium, Description: "Request body not stripped on redirect from 303", AffectedVersions: []string{"0.", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "1.12", "1.13", "1.14", "1.15", "1.16", "1.17", "1.18", "1.19", "1.20", "1.21", "1.22", "1.23", "1.24", "1.25", "1.26.0", "1.26.1", "1.26.2", "1.26.3", "1.26.4", "1.26.5", "1.26.6", "1.26.7", "1.26.8", "1.26.9", "1.26.10", "1.26.11", "1.26.12", "1.26.13", "1.26.14", "1.26.15", "1.26.16", "1.26.17"}, FixedVersion: "1.26.18"},
	},
	"cryptography": {
		{CVE: "CVE-2023-49083", Severity: SeverityHigh, Description: "NULL pointer dereference in PKCS12 parsing", AffectedVersions: []string{"0.", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12.", "13.", "14.", "15.", "16.", "17.", "18.", "19.", "20.", "21.", "22.", "23.", "24.", "25.", "26.", "27.", "28.", "29.", "30.", "31.", "32.", "33.", "34.", "35.", "36.", "37.", "38.", "39.", "40.", "41.0.0", "41.0.1", "41.0.2", "41.0.3", "41.0.4", "41.0.5"}, FixedVersion: "41.0.6"},
	},
	"pyyaml": {
		{CVE: "CVE-2020-14343", Severity: SeverityCritical, Description: "Arbitrary code execution via unsafe load", AffectedVersions: []string{"0.", "1.", "2.", "3.", "4.", "5.0", "5.1", "5.2", "5.3"}, FixedVersion: "5.4"},
	},
	"jinja2": {
		{CVE: "CVE-2024-22195", Severity: SeverityMedium, Description: "Cross-site scripting via xmlattr filter", AffectedVersions: []string{"0.", "1.", "2.", "3.0", "3.1.0", "3.1.1", "3.1.2"}, FixedVersion: "3.1.3"},
	},
	"setuptools": {
		{CVE: "CVE-2024-6345", Severity: SeverityHigh, Description: "Remote code execution via URL in package_index", AffectedVersions: []string{"0.", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12.", "13.", "14.", "15.", "16.", "17.", "18.", "19.", "20.", "21.", "22.", "23.", "24.", "25.", "26.", "27.", "28.", "29.", "30.", "31.", "32.", "33.", "34.", "35.", "36.", "37.", "38.", "39.", "40.", "41.", "42.", "43.", "44.", "45.", "46.", "47.", "48.", "49.", "50.", "51.", "52.", "53.", "54.", "55.", "56.", "57.", "58.", "59.", "60.", "61.", "62.", "63.", "64.", "65.", "66.", "67.", "68.", "69.", "70.0"}, FixedVersion: "70.1.0"},
	},
	"numpy": {
		{CVE: "CVE-2021-41495", Severity: SeverityMedium, Description: "NULL pointer dereference in numpy.sort", AffectedVersions: []string{"0.", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "1.12", "1.13", "1.14", "1.15", "1.16", "1.17", "1.18", "1.19"}, FixedVersion: "1.20.0"},
	},

	"org.apache.logging.log4j:log4j-core": {
		{CVE: "CVE-2021-44228", Severity: SeverityCritical, Description: "Log4Shell — Remote code execution via JNDI lookup", AffectedVersions: []string{"2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14.0", "2.14.1"}, FixedVersion: "2.15.0"},
		{CVE: "CVE-2021-45046", Severity: SeverityCritical, Description: "Log4Shell bypass — incomplete fix in 2.15.0", AffectedVersions: []string{"2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14", "2.15.0"}, FixedVersion: "2.16.0"},
	},
	"com.fasterxml.jackson.core:jackson-databind": {
		{CVE: "CVE-2020-36518", Severity: SeverityHigh, Description: "Denial of service via deeply nested objects", AffectedVersions: []string{"2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "2.10", "2.11", "2.12.0", "2.12.1", "2.12.2", "2.12.3", "2.12.4", "2.12.5", "2.12.6"}, FixedVersion: "2.12.7"},
	},
	"org.springframework:spring-core": {
		{CVE: "CVE-2022-22965", Severity: SeverityCritical, Description: "Spring4Shell — RCE via data binding", AffectedVersions: []string{"5.0", "5.1", "5.2", "5.3.0", "5.3.1", "5.3.2", "5.3.3", "5.3.4", "5.3.5", "5.3.6", "5.3.7", "5.3.8", "5.3.9", "5.3.10", "5.3.11", "5.3.12", "5.3.13", "5.3.14", "5.3.15", "5.3.16", "5.3.17"}, FixedVersion: "5.3.18"},
	},
}

KnownVulnerabilities maps package names to their known vulnerability entries. This covers the top 50 most commonly exploited vulnerabilities.

View Source
var ParseSeverity = types.ParseSeverity

ParseSeverity converts a string to a Severity.

View Source
var Version = strings.TrimSpace(versionFile)

Version of the inspect library. Do not edit this variable directly — bump the VERSION file at the repo root instead.

Functions

func BodyHash added in v0.1.1

func BodyHash(data []byte) string

BodyHash returns the SHA-256 hex digest of data.

func ClearCustomChecks

func ClearCustomChecks()

ClearCustomChecks removes all registered custom checks and rules. Useful in tests.

func ExitCode added in v0.1.1

func ExitCode(findings []Finding) int

ExitCode returns the appropriate CI exit code based on findings. 0 = no issues, 1 = has high/critical findings.

func GenerateHTML added in v0.1.1

func GenerateHTML(findings []Finding) string

GenerateHTML generates a styled HTML report from findings, grouped by check with severity badges and summary statistics.

func GenerateJUnit added in v0.1.1

func GenerateJUnit(findings []Finding) string

GenerateJUnit generates a JUnit XML report for CI integration.

func GenerateMarkdown added in v0.1.1

func GenerateMarkdown(findings []Finding) string

GenerateMarkdown generates a Markdown report suitable for PRs and issues.

func GenerateSARIF added in v0.1.1

func GenerateSARIF(findings []Finding, version string) string

GenerateSARIF produces a SARIF 2.1.0 JSON report from scan findings.

func GenerateSBOMJSON added in v0.1.1

func GenerateSBOMJSON(projectDir string, version string) (string, error)

GenerateSBOMJSON produces a JSON string of the SBOM.

func RegisterCheck

func RegisterCheck(c Checker)

RegisterCheck registers a custom check that will run alongside built-in checks. Call this before Scan() to include custom logic.

func RegisterRule

func RegisterRule(rule RuleCheck)

RegisterRule registers a declarative rule-based check. Rules are simpler than full Checker implementations — just pattern matching.

func SeverityStats added in v0.1.1

func SeverityStats(findings []Finding) map[string]int

SeverityStats returns a count of findings by severity level.

func ToContractFinding added in v0.1.1

func ToContractFinding(f Finding) verifycontracts.Finding

ToContractFinding converts an inspect finding into the shared verification contract.

func ToContractFindings added in v0.1.1

func ToContractFindings(findings []Finding) []verifycontracts.Finding

ToContractFindings converts inspect findings into shared verification contracts.

func ToContractReport added in v0.1.1

func ToContractReport(r *Report) *verifycontracts.Report

ToContractReport converts an inspect report into the shared verification contract.

func TruncateBody added in v0.1.1

func TruncateBody(data []byte, maxLen int) string

TruncateBody returns the first maxLen bytes of data as a string. When data exceeds maxLen, it is truncated and "..." is appended. The caller is responsible for ensuring data is valid UTF-8 if they expect text output; this function treats the bytes opaquely.

Types

type APISecurityChecker added in v0.1.1

type APISecurityChecker struct {
	BaseURL string
	Headers map[string]string
	Timeout time.Duration
}

APISecurityChecker performs security audits against REST API endpoints.

func NewAPISecurityChecker added in v0.1.1

func NewAPISecurityChecker(baseURL string) *APISecurityChecker

NewAPISecurityChecker creates an APISecurityChecker with sensible defaults.

func (*APISecurityChecker) CheckAuthHeaders added in v0.1.1

func (a *APISecurityChecker) CheckAuthHeaders(url string) []Finding

CheckAuthHeaders checks for missing security headers on API responses.

func (*APISecurityChecker) CheckCORS added in v0.1.1

func (a *APISecurityChecker) CheckCORS(url string) []Finding

CheckCORS tests for CORS misconfiguration by sending requests with various Origin headers and checking if the server reflects arbitrary origins.

func (*APISecurityChecker) CheckErrorLeakage added in v0.1.1

func (a *APISecurityChecker) CheckErrorLeakage(url string) []Finding

CheckErrorLeakage sends malformed requests and checks if error responses leak stack traces, internal paths, or version information.

func (*APISecurityChecker) CheckJWTWeakness added in v0.1.1

func (a *APISecurityChecker) CheckJWTWeakness(token string) []Finding

CheckJWTWeakness analyzes a JWT token structure for common weaknesses: none algorithm, weak signing, missing expiry, excessive claims.

func (*APISecurityChecker) CheckRateLimiting added in v0.1.1

func (a *APISecurityChecker) CheckRateLimiting(url string) []Finding

CheckRateLimiting sends rapid requests to detect missing rate limiting.

func (*APISecurityChecker) CheckVerbTampering added in v0.1.1

func (a *APISecurityChecker) CheckVerbTampering(url string) []Finding

CheckVerbTampering tests unusual HTTP methods for unexpected access.

type AXNode added in v0.1.1

type AXNode struct {
	Role        string
	Name        string
	Description string
	Value       string
	Properties  map[string]string
	Children    []AXNode
	Ignored     bool
}

AXNode represents a node in the computed accessibility tree.

type Archive added in v0.1.1

type Archive struct {
	// Version is the archive format version for forward compatibility.
	Version string `json:"version"`

	// CreatedAt is when this archive was created.
	CreatedAt time.Time `json:"created_at"`

	// ScanID is a unique identifier for the originating scan.
	ScanID string `json:"scan_id"`

	// Metadata holds summary-level information about the scan.
	Metadata ArchiveMetadata `json:"metadata"`

	// Results contains each individual scan entry.
	Results []ArchiveEntry `json:"results"`
}

Archive is a structured container for scan results, designed for durable storage and interoperability between components.

func NewArchive added in v0.1.1

func NewArchive(scanID, host string) *Archive

NewArchive creates a new Archive with the given scan ID and host, initialised to version 1.0 and the current time.

func ReadArchive added in v0.1.1

func ReadArchive(r io.Reader) (*Archive, error)

ReadArchive reads a gzipped JSON archive from r.

func (*Archive) AddEntry added in v0.1.1

func (a *Archive) AddEntry(entry ArchiveEntry)

AddEntry appends a scan result to the archive.

func (*Archive) SetMetadata added in v0.1.1

func (a *Archive) SetMetadata(meta ArchiveMetadata)

SetMetadata replaces the archive's metadata.

func (*Archive) Summary added in v0.1.1

func (a *Archive) Summary() ArchiveSummary

Summary returns an ArchiveSummary computed from the current results.

func (*Archive) WriteTo added in v0.1.1

func (a *Archive) WriteTo(w io.Writer) (int64, error)

WriteTo writes the archive as gzipped JSON to w. It implements the io.WriterTo interface.

type ArchiveEntry added in v0.1.1

type ArchiveEntry struct {
	// URL is the fully-qualified URL that was scanned.
	URL string `json:"url"`

	// StatusCode is the HTTP response status code. Zero indicates no response.
	StatusCode int `json:"status_code"`

	// ContentType is the value of the Content-Type header.
	ContentType string `json:"content_type"`

	// BodyHash is the SHA-256 hex digest of the full response body.
	BodyHash string `json:"body_hash"`

	// Headers are the full set of response headers.
	Headers http.Header `json:"headers"`

	// BodySnippet is the first 1 KB of the response body, useful for
	// quick inspection without loading the full payload.
	BodySnippet string `json:"body_snippet"`

	// Error holds the string representation of any error encountered
	// during the request. Empty when the request succeeded.
	Error string `json:"error,omitempty"`

	// ScannedAt is when this URL was scanned.
	ScannedAt time.Time `json:"scanned_at"`

	// Tags are user-defined labels for this entry (e.g. "interesting", "redirect").
	Tags []string `json:"tags,omitempty"`
}

ArchiveEntry represents one scanned URL and its response.

type ArchiveMetadata added in v0.1.1

type ArchiveMetadata struct {
	// Host is the target hostname or IP.
	Host string `json:"host"`

	// ScanDuration is how long the scan took.
	ScanDuration time.Duration `json:"scan_duration"`

	// TotalURLs is the number of URLs that were attempted.
	TotalURLs int `json:"total_urls"`

	// SuccessfulURLs is the count of URLs that returned a response.
	SuccessfulURLs int `json:"successful_urls"`

	// FailedURLs is the count of URLs that returned an error.
	FailedURLs int `json:"failed_urls"`

	// ToolVersion identifies the scanning tool version.
	ToolVersion string `json:"tool_version"`
}

ArchiveMetadata captures high-level information about the scan that produced this archive.

type ArchiveSummary added in v0.1.1

type ArchiveSummary struct {
	// TotalEntries is the number of results in the archive.
	TotalEntries int `json:"total_entries"`

	// StatusCounts maps each HTTP status code to its occurrence count.
	StatusCounts map[int]int `json:"status_counts"`

	// ContentTypeCounts maps each Content-Type to its occurrence count.
	ContentTypeCounts map[string]int `json:"content_type_counts"`

	// ErrorCount is how many entries have a non-empty Error field.
	ErrorCount int `json:"error_count"`

	// ErrorRate is ErrorCount divided by TotalEntries (0.0 when empty).
	ErrorRate float64 `json:"error_rate"`
}

ArchiveSummary provides aggregate counts from an archive's results.

type AxeNode added in v0.1.1

type AxeNode struct {
	HTML           string
	Target         []string // CSS selectors
	FailureSummary string
}

AxeNode represents a specific DOM element that violates a rule.

type AxeViolation added in v0.1.1

type AxeViolation struct {
	ID          string // rule ID (e.g., "color-contrast")
	Impact      string // "critical", "serious", "moderate", "minor"
	Description string
	Help        string
	HelpURL     string
	Nodes       []AxeNode
}

AxeViolation represents an axe-core accessibility violation.

type BrowserEngine added in v0.1.1

type BrowserEngine interface {
	RenderPage(ctx context.Context, url string, opts BrowserOpts) (*PageData, error)
	Close() error
}

BrowserEngine is the interface for optional browser-based page analysis. The core inspect package never imports rod — consumers provide an implementation via the inspect/browser sub-module.

type BrowserOpts added in v0.1.1

type BrowserOpts struct {
	Viewport   Viewport
	WaitFor    string // CSS selector to wait for before analysis
	Timeout    time.Duration
	InjectAxe  bool // inject axe-core and return accessibility violations
	Screenshot bool // capture full-page screenshot
	UserAgent  string
}

BrowserOpts configures a single browser page render.

type CIOutput added in v0.1.1

type CIOutput struct {
	Format string // "github", "gitlab", "text", "json"
}

CIOutput formats findings for CI/CD pipeline consumption. Supports: GitHub Actions annotations, GitLab CI, plain text, JSON.

func (*CIOutput) FormatFindings added in v0.1.1

func (ci *CIOutput) FormatFindings(findings []Finding) string

FormatFindings converts findings to CI-friendly output.

type Checker

type Checker interface {
	Name() string
	Run(ctx context.Context, pages []*Page) []Finding
}

Checker is the public interface for custom checks. Implement this to add your own audit logic and register it with RegisterCheck.

type DependencyChecker added in v0.1.1

type DependencyChecker struct {
	ProjectDir string
}

DependencyChecker scans project dependency files for known vulnerable packages.

func NewDependencyChecker added in v0.1.1

func NewDependencyChecker(projectDir string) *DependencyChecker

NewDependencyChecker creates a DependencyChecker for the given project directory.

func (*DependencyChecker) ScanGoMod added in v0.1.1

func (d *DependencyChecker) ScanGoMod(path string) []Finding

ScanGoMod parses a go.mod file and checks for known vulnerable package versions.

func (*DependencyChecker) ScanPackageJSON added in v0.1.1

func (d *DependencyChecker) ScanPackageJSON(path string) []Finding

ScanPackageJSON parses a package.json file and checks for known vulnerable packages.

func (*DependencyChecker) ScanRequirements added in v0.1.1

func (d *DependencyChecker) ScanRequirements(path string) []Finding

ScanRequirements parses a Python requirements.txt file and checks for known vulnerable packages.

type FileConfig

type FileConfig struct {
	Depth               int      `json:"depth"`
	Checks              []string `json:"checks"`
	Exclude             []string `json:"exclude"`
	FailOn              string   `json:"fail_on"`
	Concurrency         int      `json:"concurrency"`
	RateLimit           int      `json:"rate_limit"`
	Timeout             string   `json:"timeout"`
	PageTimeout         string   `json:"page_timeout"`
	UserAgent           string   `json:"user_agent"`
	AuthHeader          string   `json:"auth_header"`
	AuthValue           string   `json:"auth_value"`
	AcceptedStatusCodes []int    `json:"accepted_status_codes"`
}

FileConfig represents the contents of an .inspect.toml configuration file.

type Finding

type Finding struct {
	Check    string   `json:"check"`
	Severity Severity `json:"severity"`
	URL      string   `json:"url"`
	Element  string   `json:"element,omitempty"`
	Message  string   `json:"message"`
	Fix      string   `json:"fix,omitempty"`
	Evidence string   `json:"evidence,omitempty"`
}

Finding represents a single issue detected during a scan.

type FindingEntry added in v0.1.1

type FindingEntry struct {
	ScanID    string    `json:"scan_id"`
	URL       string    `json:"url"`
	CheckName string    `json:"check_name"`
	Passed    bool      `json:"passed"`
	Severity  string    `json:"severity"`
	Message   string    `json:"message"`
	Details   string    `json:"details,omitempty"`
	Tags      []string  `json:"tags,omitempty"`
	ScannedAt time.Time `json:"scanned_at"`
}

FindingEntry is a single finding record for the external store.

func ConvertArchiveToEntries added in v0.1.1

func ConvertArchiveToEntries(archive *Archive) []FindingEntry

ConvertArchiveToEntries converts the results in an Archive into FindingEntry records suitable for the store.

func ConvertScanResult added in v0.1.1

func ConvertScanResult(url string, findings []Finding) []FindingEntry

ConvertScanResult converts a slice of Finding records from a scan into FindingEntry records for the store.

type FindingSink added in v0.1.1

type FindingSink interface {
	Store(ctx context.Context, entry FindingEntry) error
	StoreBatch(ctx context.Context, entries []FindingEntry) error
}

FindingSink is the interface for external stores that persist scan findings. Implementations should be safe for concurrent use by multiple goroutines.

type FindingsStore added in v0.1.1

type FindingsStore struct {
	// contains filtered or unexported fields
}

FindingsStore buffers scan findings and flushes them to a FindingSink in batches for efficiency.

func NewFindingsStore added in v0.1.1

func NewFindingsStore(sink FindingSink, opts ...FindingsStoreOption) *FindingsStore

NewFindingsStore creates a FindingsStore backed by the given sink. If sink is nil, all operations are no-ops.

func (*FindingsStore) Add added in v0.1.1

func (s *FindingsStore) Add(ctx context.Context, entry FindingEntry) error

Add appends an entry to the buffer. If autoFlush is enabled and the buffer has reached batchSize, the buffer is flushed to the sink. A nil sink causes Add to return immediately with no error.

func (*FindingsStore) Flush added in v0.1.1

func (s *FindingsStore) Flush(ctx context.Context) error

Flush sends all buffered entries to the sink and clears the buffer. A nil sink causes Flush to clear the buffer without error.

func (*FindingsStore) Size added in v0.1.1

func (s *FindingsStore) Size() int

Size returns the number of entries currently in the buffer.

type FindingsStoreOption added in v0.1.1

type FindingsStoreOption func(*FindingsStore)

FindingsStoreOption configures a FindingsStore.

func WithAutoFlush added in v0.1.1

func WithAutoFlush(enabled bool) FindingsStoreOption

WithAutoFlush controls whether the store automatically flushes when the buffer reaches batchSize. When disabled, callers must call Flush explicitly.

func WithBatchSize added in v0.1.1

func WithBatchSize(n int) FindingsStoreOption

WithBatchSize sets the number of buffered entries that triggers an automatic flush. Values less than 1 are corrected to 1.

type JWTClaims added in v0.1.1

type JWTClaims struct {
	Header  map[string]interface{}
	Payload map[string]interface{}
}

JWTClaims represents decoded JWT claims for analysis.

func ParseJWT added in v0.1.1

func ParseJWT(token string) (*JWTClaims, error)

ParseJWT decodes a JWT token without signature validation (for analysis purposes).

type LLMSecurityScanner added in v0.1.1

type LLMSecurityScanner struct {
	// contains filtered or unexported fields
}

LLMSecurityScanner enhances traditional SAST with LLM-based analysis. Research shows LLM+SAST hybrid reduces false positives by 91% (SAST-Genius, IEEE S&P 2025).

func NewLLMSecurityScanner added in v0.1.1

func NewLLMSecurityScanner() *LLMSecurityScanner

NewLLMSecurityScanner creates a security scanner with built-in checks.

func (*LLMSecurityScanner) BuildEnhancedPrompt added in v0.1.1

func (s *LLMSecurityScanner) BuildEnhancedPrompt(findings []SecurityFinding, source string) string

BuildEnhancedPrompt builds a prompt that combines SAST findings with LLM analysis capabilities. This is the key innovation from SAST-Genius.

func (*LLMSecurityScanner) Scan added in v0.1.1

func (s *LLMSecurityScanner) Scan(ctx context.Context, source string, filePath string) []SecurityFinding

Scan runs all security checks on the given source code.

type NetworkEntry added in v0.1.1

type NetworkEntry struct {
	URL        string
	Method     string
	Status     int
	MimeType   string
	Size       int64
	Duration   time.Duration
	Failed     bool
	FailReason string
}

NetworkEntry represents a network request made during page load.

type Option

type Option interface {
	// contains filtered or unexported methods
}

Option configures a scan operation.

var CI Option = optFunc(func(c *config) {
	c.depth = 5
	c.checks = []string{"links", "security", "forms", "a11y", "perf", "seo"}
	c.concurrency = 10
	c.failOn = SeverityHigh
})

CI configures for continuous integration: standard checks, fail on high, JSON output.

var Deep Option = optFunc(func(c *config) {
	c.depth = 0
	c.checks = []string{"links", "security", "forms", "a11y", "perf", "seo"}
	c.concurrency = 20
})

Deep performs an exhaustive crawl with no depth limit.

var Quick Option = optFunc(func(c *config) {
	c.depth = 2
	c.checks = []string{"links"}
	c.concurrency = 5
})

Quick performs a shallow crawl checking only broken links.

var SecurityOnly Option = optFunc(func(c *config) {
	c.checks = []string{"security"}
})

Security limits the scan to security-related checks.

var Standard Option = optFunc(func(c *config) {
	c.depth = 5
	c.checks = []string{"links", "security", "forms", "a11y", "perf", "seo"}
	c.concurrency = 10
})

Standard performs a balanced crawl with the six default checks enabled.

func LoadConfig

func LoadConfig(dir string) ([]Option, error)

LoadConfig reads .inspect.toml or .inspect.yaml from the given directory (searching upward to parent directories). Returns nil options and nil error if no config file is found. Returns an error only on malformed files.

func WithAcceptedStatusCodes

func WithAcceptedStatusCodes(codes ...int) Option

WithAcceptedStatusCodes sets the HTTP status codes considered acceptable by the link checker. By default (when no codes are specified), status codes 200-399 are accepted.

func WithAllowPrivateIPs added in v0.1.1

func WithAllowPrivateIPs() Option

WithAllowPrivateIPs disables SSRF protection for private IP ranges. Use this only when intentionally scanning internal infrastructure.

func WithAuth

func WithAuth(header, value string) Option

func WithBlockPrivateIPs added in v0.1.1

func WithBlockPrivateIPs() Option

WithBlockPrivateIPs enables SSRF protection that blocks requests to private IP ranges. Enabled by default to prevent SSRF attacks. Call WithAllowPrivateIPs() to disable when intentionally scanning internal infrastructure.

func WithBrowser added in v0.1.1

func WithBrowser(engine BrowserEngine) Option

WithBrowser sets a BrowserEngine for browser-rendered page analysis. When set, the scanner uses the engine to render pages with full JavaScript execution instead of relying solely on raw HTTP fetches for HTML analysis. The browser sub-module (github.com/GrayCodeAI/inspect/browser) provides a rod-based implementation.

func WithChecks

func WithChecks(checks ...string) Option

func WithCircuitBreaker added in v0.1.1

func WithCircuitBreaker(enabled bool, threshold int, cooldown time.Duration) Option

WithCircuitBreaker enables a per-host circuit breaker that stops sending requests to a host after threshold consecutive failures. The breaker half-opens after cooldown to allow a single probe request. Pass enabled=false to explicitly disable even if previously enabled.

func WithConcurrency

func WithConcurrency(n int) Option

func WithCookieJar

func WithCookieJar(jar http.CookieJar) Option

func WithCustomChecks added in v0.1.1

func WithCustomChecks(checks ...Checker) Option

WithCustomChecks registers custom checks that run alongside built-in checks. Unlike the global RegisterCheck, these are scoped to the Scanner instance.

func WithCustomRules added in v0.1.1

func WithCustomRules(rules ...RuleCheck) Option

WithCustomRules registers declarative rule-based checks scoped to this Scanner. Unlike the global RegisterRule, these are scoped to the Scanner instance.

func WithDepth

func WithDepth(n int) Option

func WithExclude

func WithExclude(patterns ...string) Option

func WithFailOn

func WithFailOn(sev Severity) Option

func WithFollowRedirects

func WithFollowRedirects(max int) Option

func WithLogger

func WithLogger(l *slog.Logger) Option

func WithMaxPages added in v0.1.1

func WithMaxPages(n int) Option

WithMaxPages sets the maximum number of pages to crawl. Defaults to 10000. Set to 0 for no limit.

func WithPageTimeout

func WithPageTimeout(d time.Duration) Option

func WithRateLimit

func WithRateLimit(reqPerSec int) Option

func WithRespectRobots

func WithRespectRobots(enabled bool) Option

func WithTemplateDir added in v0.1.1

func WithTemplateDir(dir string) Option

WithTemplateDir loads all YAML templates from a directory as scan-scoped rules.

func WithTemplateFile added in v0.1.1

func WithTemplateFile(path string) Option

WithTemplateFile loads declarative check templates from a YAML file and registers them as scan-scoped rules. A parse error is surfaced lazily as a rule named "<template-load-error>" so callers using the functional-option form still observe the failure during scanning configuration.

func WithTimeout

func WithTimeout(d time.Duration) Option

func WithUserAgent

func WithUserAgent(ua string) Option

type Page

type Page struct {
	URL        string
	StatusCode int
	Headers    map[string]string
	Body       []byte
	Links      []PageLink
	Depth      int
	ParentURL  string
}

Page is the public representation of a crawled page, exposed to custom checks.

type PageData added in v0.1.1

type PageData struct {
	FinalURL      string
	Title         string
	RenderedHTML  string
	AccessTree    []AXNode
	AxeViolations []AxeViolation
	ConsoleErrors []string
	NetworkLog    []NetworkEntry
	Screenshot    []byte
	LoadTime      time.Duration
}

PageData holds results from browser-rendered page analysis.

type PageLink struct {
	Href     string
	Text     string
	External bool
}

PageLink represents a link found on a page.

type RateLimiter added in v0.1.1

type RateLimiter struct {
	// contains filtered or unexported fields
}

RateLimiter provides per-host rate limiting for crawl requests. Each host gets its own token-bucket limiter so that aggressive crawling of one host does not throttle requests to others. Stale limiters are cleaned up periodically.

func NewRateLimiter added in v0.1.1

func NewRateLimiter(rps float64, burst int, opts ...RateLimiterOption) *RateLimiter

NewRateLimiter creates a per-host rate limiter that allows rps requests per second with the given burst size. Each host that is seen gets its own independent limiter. Background cleanup removes limiters for hosts that have not been accessed in 5 minutes.

func (*RateLimiter) ActiveHosts added in v0.1.1

func (rl *RateLimiter) ActiveHosts() int

ActiveHosts returns the number of hosts currently being tracked.

func (*RateLimiter) Allow added in v0.1.1

func (rl *RateLimiter) Allow(host string) bool

Allow reports whether a request for host is allowed right now without blocking. Returns true if the request may proceed.

func (*RateLimiter) Close added in v0.1.1

func (rl *RateLimiter) Close()

Close stops the background cleanup goroutine. After Close is called the limiter should not be used.

func (*RateLimiter) Wait added in v0.1.1

func (rl *RateLimiter) Wait(ctx context.Context, host string) error

Wait blocks until a request for host is allowed or ctx is cancelled.

type RateLimiterOption added in v0.1.1

type RateLimiterOption func(*RateLimiter)

RateLimiterOption is a functional option for configuring a RateLimiter.

func WithCleanupInterval added in v0.1.1

func WithCleanupInterval(d time.Duration) RateLimiterOption

WithCleanupInterval sets how often stale host limiters are reaped. A host is considered stale when it has not been used for 5 minutes. The default cleanup interval is 1 minute.

type Report

type Report struct {
	Target      string        `json:"target"`
	Findings    []Finding     `json:"findings"`
	Stats       Stats         `json:"stats"`
	CrawledURLs int           `json:"crawled_urls"`
	Duration    time.Duration `json:"duration"`
	FailOn      Severity      `json:"fail_on"`
}

Report is the complete result of a scan operation.

func Scan

func Scan(ctx context.Context, target string, opts ...Option) (*Report, error)

Scan crawls the target URL and runs all configured checks. This is the primary entry point for one-off scans.

func (*Report) Failed

func (r *Report) Failed() bool

Failed returns true if any finding meets or exceeds the configured fail threshold.

func (*Report) MaxSeverity

func (r *Report) MaxSeverity() Severity

MaxSeverity returns the highest severity found in the report.

type RuleCheck

type RuleCheck struct {
	RuleName     string
	RuleSeverity Severity
	Description  string
	// Match conditions (any match triggers a finding)
	HeaderMatch   map[string]string // header name → regex pattern (match = issue)
	HeaderMissing []string          // headers that MUST be present
	BodyMatch     []string          // regex patterns in body (match = issue)
	BodyMissing   []string          // regex patterns that MUST be present
	URLMatch      string            // only apply to URLs matching this regex
	StatusCodes   []int             // only apply to these status codes (empty = all)
	FixSuggestion string
}

RuleCheck defines a declarative check via patterns — no Go code required. This is the equivalent of Nuclei templates but for site auditing.

func LoadTemplateDir added in v0.1.1

func LoadTemplateDir(dir string) ([]RuleCheck, error)

LoadTemplateDir loads all .yaml/.yml templates in a directory (non-recursive).

func LoadTemplateFile added in v0.1.1

func LoadTemplateFile(path string) ([]RuleCheck, error)

LoadTemplateFile reads and parses a single YAML template file.

func ParseTemplates added in v0.1.1

func ParseTemplates(data []byte) ([]RuleCheck, error)

ParseTemplates decodes one or more templates from YAML bytes into RuleChecks.

type SBOMComponent added in v0.1.1

type SBOMComponent struct {
	Type    string `json:"type"`
	Name    string `json:"name"`
	Version string `json:"version"`
	PURL    string `json:"purl,omitempty"`
	Scope   string `json:"scope,omitempty"`
}

SBOMComponent represents a software component/dependency.

type SBOMDocument added in v0.1.1

type SBOMDocument struct {
	BOMFormat    string          `json:"bomFormat"`
	SpecVersion  string          `json:"specVersion"`
	SerialNumber string          `json:"serialNumber,omitempty"`
	Version      int             `json:"version"`
	Metadata     SBOMMetadata    `json:"metadata"`
	Components   []SBOMComponent `json:"components"`
}

SBOMDocument represents a CycloneDX 1.5 Software Bill of Materials.

func GenerateSBOM added in v0.1.1

func GenerateSBOM(projectDir string, version string) (*SBOMDocument, error)

GenerateSBOM produces a CycloneDX 1.5 SBOM from project dependency files.

type SBOMMetadata added in v0.1.1

type SBOMMetadata struct {
	Timestamp string         `json:"timestamp"`
	Tools     []SBOMTool     `json:"tools,omitempty"`
	Component *SBOMComponent `json:"component,omitempty"`
}

SBOMMetadata contains metadata about the SBOM.

type SBOMTool added in v0.1.1

type SBOMTool struct {
	Vendor  string `json:"vendor"`
	Name    string `json:"name"`
	Version string `json:"version"`
}

SBOMTool describes the tool that generated the SBOM.

type Scanner

type Scanner struct {
	// contains filtered or unexported fields
}

Scanner is a reusable site auditor. Create one with NewScanner and call Scan multiple times. It is safe for concurrent use.

func NewScanner

func NewScanner(opts ...Option) *Scanner

NewScanner creates a configured Scanner. Apply presets and options:

s := inspect.NewScanner(inspect.Standard, inspect.WithDepth(3))

func (*Scanner) Scan

func (s *Scanner) Scan(ctx context.Context, target string) (*Report, error)

Scan crawls the target URL and runs all configured checks against the discovered pages. Returns a complete Report with findings and stats.

func (*Scanner) ScanDir

func (s *Scanner) ScanDir(ctx context.Context, dir string) (*Report, error)

ScanDir scans a local directory by starting a temporary file server. Useful for auditing build output before deployment.

type SecurityCheck added in v0.1.1

type SecurityCheck struct {
	ID          string
	Name        string
	Description string
	Category    string // "injection", "auth", "crypto", "config", "data"
	Severity    string // "critical", "high", "medium", "low"
	Check       func(ctx context.Context, source string, filePath string) []SecurityFinding
}

SecurityCheck represents a security check.

type SecurityFinding added in v0.1.1

type SecurityFinding struct {
	CheckID    string  `json:"check_id"`
	Rule       string  `json:"rule"`
	Message    string  `json:"message"`
	File       string  `json:"file"`
	Line       int     `json:"line"`
	Severity   string  `json:"severity"`
	Confidence float64 `json:"confidence"` // 0-1
	CWE        string  `json:"cwe"`        // CWE ID if applicable
	Evidence   string  `json:"evidence"`
	Suggestion string  `json:"suggestion"` // how to fix
}

SecurityFinding represents a security finding.

type Severity

type Severity = types.Severity

Severity represents the impact level of a finding. Aliased from shared types for cross-module compatibility.

const (
	SeverityInfo     Severity = types.SeverityInfo
	SeverityLow      Severity = types.SeverityLow
	SeverityMedium   Severity = types.SeverityMedium
	SeverityHigh     Severity = types.SeverityHigh
	SeverityCritical Severity = types.SeverityCritical
)

Severity constants re-exported for convenience.

type Stats

type Stats struct {
	PagesScanned     int                      `json:"pages_scanned"`
	FindingsTotal    int                      `json:"findings_total"`
	BySeverity       map[Severity]int         `json:"by_severity"`
	ByCheck          map[string]int           `json:"by_check"`
	DurationPerCheck map[string]time.Duration `json:"duration_per_check"`
}

Stats provides scan metrics, broken down by severity and check type.

type Template added in v0.1.1

type Template struct {
	Name          string            `yaml:"name"`
	Severity      string            `yaml:"severity"`
	Description   string            `yaml:"description"`
	HeaderMatch   map[string]string `yaml:"header_match,omitempty"`
	HeaderMissing []string          `yaml:"header_missing,omitempty"`
	BodyMatch     []string          `yaml:"body_match,omitempty"`
	BodyMissing   []string          `yaml:"body_missing,omitempty"`
	URLMatch      string            `yaml:"url_match,omitempty"`
	StatusCodes   []int             `yaml:"status_codes,omitempty"`
	Fix           string            `yaml:"fix,omitempty"`
}

Template is the YAML representation of a declarative RuleCheck. A single YAML file may contain one template (a mapping) or several (a top-level "templates" list). This is inspect's equivalent of Nuclei templates: define a check with pattern matching, no Go code required.

Example:

name: missing-hsts
severity: high
description: Strict-Transport-Security header is missing
header_missing: [Strict-Transport-Security]
fix: Add a Strict-Transport-Security response header

type Viewport added in v0.1.1

type Viewport struct {
	Width  int
	Height int
	Mobile bool
}

Viewport specifies the browser viewport dimensions.

type VulnEntry added in v0.1.1

type VulnEntry struct {
	CVE              string
	Severity         Severity
	Description      string
	AffectedVersions []string // versions that are affected (prefix match)
	FixedVersion     string
}

VulnEntry represents a known vulnerability for a package version range.

Directories

Path Synopsis
examples
basic command
internal
check
Package check implements the check registry and individual site audit checks.
Package check implements the check registry and individual site audit checks.
crawler
Package crawler implements a concurrent website crawler with rate limiting, depth control, URL deduplication, and robots.txt compliance.
Package crawler implements a concurrent website crawler with rate limiting, depth control, URL deduplication, and robots.txt compliance.
report
Package report provides formatting utilities for scan results.
Package report provides formatting utilities for scan results.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL