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 ¶
- Variables
- func CheckRedirect(req *http.Request, via []*http.Request) error
- func GuardedDial(ctx context.Context, network, addr string) (net.Conn, error)
- func NewRequest(ctx context.Context, method, url string, body []byte) (*http.Request, error)
- type CallOpts
- type Client
- func (c *Client) Correlate() bool
- func (c *Client) Do(req *http.Request, o CallOpts) (*Response, error)
- func (c *Client) Intrusive() bool
- func (c *Client) Live() bool
- func (c *Client) MinFootprint() bool
- func (c *Client) Planned() []PlannedCall
- func (c *Client) RegisterSecret(s string)
- func (c *Client) RegisterSecretRef(s, repl string)
- func (c *Client) SetCorrelate(v bool)
- func (c *Client) SetIntrusive(v bool)
- func (c *Client) SetMinFootprint(v bool)
- func (c *Client) SetTrace(v bool)
- type PlannedCall
- type Response
Constants ¶
This section is empty.
Variables ¶
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).
var ErrMutatingCall = errors.New("recon: refused non-read-only request")
ErrMutatingCall is returned when a module attempts a non-read-only request.
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
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 ¶
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.
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 ¶
New returns a client. When live is false the client records calls instead of sending them.
func (*Client) Do ¶
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 ¶
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) MinFootprint ¶
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 ¶
RegisterSecret marks a value as secret so it is scrubbed (to a redacted form) from every recorded URL and header.
func (*Client) RegisterSecretRef ¶
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 ¶
SetCorrelate enables reading bounded local hints (SSH config/known_hosts/ shell history) to correlate keys to candidate hosts.
func (*Client) SetIntrusive ¶
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 ¶
SetMinFootprint enables OPSEC mode: modules should run only their identity call and skip the inventory/count fan-out.
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.