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
- Variables
- func BodyHash(data []byte) string
- func ClearCustomChecks()
- func ExitCode(findings []Finding) int
- func GenerateHTML(findings []Finding) string
- func GenerateJUnit(findings []Finding) string
- func GenerateMarkdown(findings []Finding) string
- func GenerateSARIF(findings []Finding, version string) string
- func GenerateSBOMJSON(projectDir string, version string) (string, error)
- func RegisterCheck(c Checker)
- func RegisterRule(rule RuleCheck)
- func SeverityStats(findings []Finding) map[string]int
- func ToContractFinding(f Finding) verifycontracts.Finding
- func ToContractFindings(findings []Finding) []verifycontracts.Finding
- func ToContractReport(r *Report) *verifycontracts.Report
- func TruncateBody(data []byte, maxLen int) string
- type APISecurityChecker
- func (a *APISecurityChecker) CheckAuthHeaders(url string) []Finding
- func (a *APISecurityChecker) CheckCORS(url string) []Finding
- func (a *APISecurityChecker) CheckErrorLeakage(url string) []Finding
- func (a *APISecurityChecker) CheckJWTWeakness(token string) []Finding
- func (a *APISecurityChecker) CheckRateLimiting(url string) []Finding
- func (a *APISecurityChecker) CheckVerbTampering(url string) []Finding
- type AXNode
- type Archive
- type ArchiveEntry
- type ArchiveMetadata
- type ArchiveSummary
- type AxeNode
- type AxeViolation
- type BrowserEngine
- type BrowserOpts
- type CIOutput
- type Checker
- type DependencyChecker
- type FileConfig
- type Finding
- type FindingEntry
- type FindingSink
- type FindingsStore
- type FindingsStoreOption
- type JWTClaims
- type LLMSecurityScanner
- type NetworkEntry
- type Option
- func LoadConfig(dir string) ([]Option, error)
- func WithAcceptedStatusCodes(codes ...int) Option
- func WithAllowPrivateIPs() Option
- func WithAuth(header, value string) Option
- func WithBlockPrivateIPs() Option
- func WithBrowser(engine BrowserEngine) Option
- func WithChecks(checks ...string) Option
- func WithCircuitBreaker(enabled bool, threshold int, cooldown time.Duration) Option
- func WithConcurrency(n int) Option
- func WithCookieJar(jar http.CookieJar) Option
- func WithCustomChecks(checks ...Checker) Option
- func WithCustomRules(rules ...RuleCheck) Option
- func WithDepth(n int) Option
- func WithExclude(patterns ...string) Option
- func WithFailOn(sev Severity) Option
- func WithFollowRedirects(max int) Option
- func WithLogger(l *slog.Logger) Option
- func WithMaxPages(n int) Option
- func WithPageTimeout(d time.Duration) Option
- func WithRateLimit(reqPerSec int) Option
- func WithRespectRobots(enabled bool) Option
- func WithTemplateDir(dir string) Option
- func WithTemplateFile(path string) Option
- func WithTimeout(d time.Duration) Option
- func WithUserAgent(ua string) Option
- type Page
- type PageData
- type PageLink
- type RateLimiter
- type RateLimiterOption
- type Report
- type RuleCheck
- type SBOMComponent
- type SBOMDocument
- type SBOMMetadata
- type SBOMTool
- type Scanner
- type SecurityCheck
- type SecurityFinding
- type Severity
- type Stats
- type Template
- type Viewport
- type VulnEntry
Constants ¶
const ArchiveVersion = "1.0"
ArchiveVersion is the current archive format version.
Variables ¶
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.
var ParseSeverity = types.ParseSeverity
ParseSeverity converts a string to a Severity.
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 ClearCustomChecks ¶
func ClearCustomChecks()
ClearCustomChecks removes all registered custom checks and rules. Useful in tests.
func ExitCode ¶ added in v0.1.1
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
GenerateHTML generates a styled HTML report from findings, grouped by check with severity badges and summary statistics.
func GenerateJUnit ¶ added in v0.1.1
GenerateJUnit generates a JUnit XML report for CI integration.
func GenerateMarkdown ¶ added in v0.1.1
GenerateMarkdown generates a Markdown report suitable for PRs and issues.
func GenerateSARIF ¶ added in v0.1.1
GenerateSARIF produces a SARIF 2.1.0 JSON report from scan findings.
func GenerateSBOMJSON ¶ added in v0.1.1
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
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
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
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
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
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.
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 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
FormatFindings converts findings to CI-friendly output.
type Checker ¶
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 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.
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 ¶
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 ¶
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 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 WithCircuitBreaker ¶ added in v0.1.1
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 WithCookieJar ¶
func WithCustomChecks ¶ added in v0.1.1
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
WithCustomRules registers declarative rule-based checks scoped to this Scanner. Unlike the global RegisterRule, these are scoped to the Scanner instance.
func WithExclude ¶
func WithFailOn ¶
func WithFollowRedirects ¶
func WithLogger ¶
func WithMaxPages ¶ added in v0.1.1
WithMaxPages sets the maximum number of pages to crawl. Defaults to 10000. Set to 0 for no limit.
func WithPageTimeout ¶
func WithRateLimit ¶
func WithRespectRobots ¶
func WithTemplateDir ¶ added in v0.1.1
WithTemplateDir loads all YAML templates from a directory as scan-scoped rules.
func WithTemplateFile ¶ added in v0.1.1
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 WithUserAgent ¶
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 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.
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 ¶
Scan crawls the target URL and runs all configured checks. This is the primary entry point for one-off scans.
func (*Report) Failed ¶
Failed returns true if any finding meets or exceeds the configured fail threshold.
func (*Report) MaxSeverity ¶
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
LoadTemplateDir loads all .yaml/.yml templates in a directory (non-recursive).
func LoadTemplateFile ¶ added in v0.1.1
LoadTemplateFile reads and parses a single YAML template file.
func ParseTemplates ¶ added in v0.1.1
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 ¶
NewScanner creates a configured Scanner. Apply presets and options:
s := inspect.NewScanner(inspect.Standard, inspect.WithDepth(3))
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 ¶
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
Source Files
¶
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. |