recon

package
v1.11.0 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package recon provides the single HTTP client every module uses for recon.

It enforces Geiger's safety model structurally: only GET/HEAD are allowed, plus POST when explicitly opted in via CallOpts.ReadOnlyPOST (the documented introspection carve-outs and the one auth token exchange). Any other method, or a POST without the opt-in, is refused before a packet leaves the host.

In dry-run mode (the default) the client records each planned call and returns a synthetic response instead of hitting the network.

Index

Constants

This section is empty.

Variables

View Source
var ErrBlockedTarget = errors.New("recon: refused cloud-metadata target (possible SSRF)")

ErrBlockedTarget is returned when recon would dial a cloud metadata address. An input-controlled endpoint/DSN — or a harvested value re-triaged internally — must not be usable to reach the instance metadata service (SSRF to steal instance credentials).

View Source
var ErrMutatingCall = errors.New("recon: refused non-read-only request")

ErrMutatingCall is returned when a module attempts a non-read-only request.

View Source
var UserAgent = "geiger"

UserAgent is sent on every recon request that doesn't already set one. The CLI sets it to "geiger/<version>" (overridable via --user-agent). A clear, branded agent matches geiger's read-only, authorized-use, no-evasion stance and lets defenders attribute the calls in their own logs.

Functions

func CheckRedirect added in v1.8.0

func CheckRedirect(req *http.Request, via []*http.Request) error

CheckRedirect is the redirect policy for every geiger HTTP client.

Go's own policy drops Authorization and Cookie when the host changes but forwards custom headers, which is exactly where geiger carries most of its credentials. An endpoint read out of scanned data — or any endpoint that has been compromised — could therefore 302 a credential to an attacker-chosen host. Here a change of hostname strips every header outside the allowlist, so a redirect can move the request but never the secret.

Only the hostname is compared: a redirect that upgrades http→https or changes port on the same host is routine and keeps its headers.

func GuardedDial

func GuardedDial(ctx context.Context, network, addr string) (net.Conn, error)

GuardedDial is a net.Dialer DialContext that resolves the target, refuses it if ANY resolved address is blocked, then dials a vetted IP literal (no TOCTOU re-resolve). Use it as http.Transport.DialContext for any HTTP-speaking recon client so an attacker-controlled host can't redirect it at metadata/loopback.

func NewRequest

func NewRequest(ctx context.Context, method, url string, body []byte) (*http.Request, error)

NewRequest builds a GET request with a context (convenience).

Types

type CallOpts

type CallOpts struct {
	// ReadOnlyPOST permits a POST for the documented carve-outs only:
	// STS GetCallerIdentity, k8s SelfSubjectRulesReview, Slack auth.test,
	// read-only SQL/GraphQL queries, and the single auth token exchange.
	ReadOnlyPOST bool
	// Note describes why a POST is read-only, recorded in the plan/audit.
	Note string
}

CallOpts modifies a single request.

type Client

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

Client is the read-only-enforcing HTTP client.

func New

func New(h *http.Client, live bool) *Client

New returns a client. When live is false the client records calls instead of sending them.

func (*Client) Correlate

func (c *Client) Correlate() bool

Correlate reports whether local-hint correlation is enabled.

func (*Client) Do

func (c *Client) Do(req *http.Request, o CallOpts) (*Response, error)

Do executes (live) or records (dry-run) a request after the read-only check. In dry-run it returns a synthetic 200 with an empty body and DryRun set.

func (*Client) Intrusive

func (c *Client) Intrusive() bool

Intrusive reports whether invasive read-only actions are permitted. A module must check this (in addition to Live) before connecting to a database, hitting a cluster API, or harvesting downstream secrets.

func (*Client) Live

func (c *Client) Live() bool

Live reports whether the client makes real network calls.

func (*Client) MinFootprint

func (c *Client) MinFootprint() bool

MinFootprint reports whether modules should minimize their call count.

func (*Client) Planned

func (c *Client) Planned() []PlannedCall

Planned returns the recorded calls (dry-run, or audit trail in live mode).

func (*Client) RegisterSecret

func (c *Client) RegisterSecret(s string)

RegisterSecret marks a value as secret so it is scrubbed (to a redacted form) from every recorded URL and header.

func (*Client) RegisterSecretRef

func (c *Client) RegisterSecretRef(s, repl string)

RegisterSecretRef is like RegisterSecret but displays the secret as repl (e.g. "$OPENAI_API_KEY") so the rendered curl is runnable after the variable is exported, without ever printing the value.

func (*Client) SetCorrelate

func (c *Client) SetCorrelate(v bool)

SetCorrelate enables reading bounded local hints (SSH config/known_hosts/ shell history) to correlate keys to candidate hosts.

func (*Client) SetIntrusive

func (c *Client) SetIntrusive(v bool)

SetIntrusive enables read-only-but-invasive actions (DB connect, k8s live API). Off by default; the CLI turns it on with --intrusive.

func (*Client) SetMinFootprint

func (c *Client) SetMinFootprint(v bool)

SetMinFootprint enables OPSEC mode: modules should run only their identity call and skip the inventory/count fan-out.

func (*Client) SetTrace

func (c *Client) SetTrace(v bool)

SetTrace enables capturing the (masked) response body of each live call.

type PlannedCall

type PlannedCall struct {
	Method     string
	URL        string
	Headers    map[string]string // values redacted
	Body       string            // redacted request body (for non-GET calls)
	Note       string            // optional human description, e.g. "auth token exchange"
	RespStatus int               // captured only under --trace
	RespBody   string            // masked, truncated response body (--trace only)
}

PlannedCall is a recorded request (used for dry-run output and audit).

func (PlannedCall) Curl

func (p PlannedCall) Curl() string

Curl renders the planned call as a copy-pasteable curl command. Secrets appear either as a redacted form or, when known, as a shell variable reference (e.g. $OPENAI_API_KEY) — never the raw value. Args that reference a variable are double-quoted so the shell expands them.

type Response

type Response struct {
	Status int
	Header http.Header
	Body   []byte
	DryRun bool
	// contains filtered or unexported fields
}

Response is a recon response (real or synthetic in dry-run).

Jump to

Keyboard shortcuts

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