Documentation
¶
Index ¶
- Variables
- func BaselineLinksNeighbor(baselineBody, neighborTarget string) bool
- func ClassifyParamValue(value string) (IDType, Predictability, int)
- func ClassifyPathContext(pathSegments []string, segmentValue string) (string, int)
- func ContainsEnforcementString(body string) bool
- func GenerateNeighborIDs(baseValue string, idType IDType, count int) []string
- func IsAuthChallengePage(body string) bool
- func IsLoginRedirect(statusCode int, location string) bool
- func NormalizeName(name string) string
- func RequestCarriesCredential(req *httpmsg.HttpRequest) bool
- type AuthzVerdict
- type CompareOptions
- type IDClassification
- type IDType
- type NameSignal
- type Predictability
- type ResponseComparison
- type ResponseSummary
Constants ¶
This section is empty.
Variables ¶
var ( SequentialIntPattern = regexp.MustCompile(`^\d{1,10}$`) StructuredCodePattern = regexp.MustCompile(`(?i)^[A-Z]{1,4}-\d{3,10}(-\d+)?$`) UUIDv1Pattern = regexp.MustCompile(`(?i)^[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`) UUIDv4Pattern = regexp.MustCompile(`(?i)^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`) HexPattern = regexp.MustCompile(`(?i)^[0-9a-f]{16,64}$`) EmailPattern = regexp.MustCompile(`(?i)^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`) )
Value classification patterns.
var EnforcementStrings = []string{
"unauthorized",
"forbidden",
"access denied",
"access_denied",
"not authorized",
"not_authorized",
"permission denied",
"permission_denied",
"insufficient privileges",
"insufficient permissions",
"requires authentication",
"authentication required",
"login required",
"you do not have permission",
"you don't have permission",
"not allowed",
"no access",
"invalid token",
"token expired",
}
EnforcementStrings are substrings in response bodies that indicate authorization enforcement.
var HighSignalNames = map[string]struct{}{
"id": {},
"uid": {},
"user_id": {},
"userid": {},
"account_id": {},
"accountid": {},
"order_id": {},
"orderid": {},
"profile_id": {},
"profileid": {},
"customer_id": {},
"customerid": {},
"record_id": {},
"recordid": {},
"doc_id": {},
"docid": {},
"invoice_id": {},
"invoiceid": {},
"transaction_id": {},
"transactionid": {},
"file_id": {},
"fileid": {},
"message_id": {},
"messageid": {},
"comment_id": {},
"commentid": {},
"project_id": {},
"projectid": {},
"team_id": {},
"teamid": {},
"org_id": {},
"orgid": {},
"report_id": {},
"reportid": {},
"ticket_id": {},
"ticketid": {},
"session_id": {},
"sessionid": {},
}
HighSignalNames are parameter names that strongly indicate object identifiers.
var IDSuffixPattern = regexp.MustCompile(`(?i)(.*_)?(id|Id|ID)$`)
IDSuffixPattern matches parameter names ending with _id, Id, or ID.
var LoginRedirectPatterns = []string{
"/login",
"/signin",
"/sign-in",
"/auth/login",
"/auth/signin",
"/sso/",
"/oauth/",
"/cas/login",
}
LoginRedirectPatterns are URL path prefixes that indicate a login redirect.
var MediumSignalNames = map[string]struct{}{
"num": {},
"number": {},
"no": {},
"ref": {},
"key": {},
"token": {},
"code": {},
"handle": {},
"slug": {},
"uuid": {},
"guid": {},
}
MediumSignalNames are parameter names that may indicate identifiers but are less specific.
var ResourceNouns = map[string]struct{}{
"users": {},
"accounts": {},
"orders": {},
"profiles": {},
"customers": {},
"invoices": {},
"documents": {},
"messages": {},
"files": {},
"tickets": {},
"projects": {},
"reports": {},
"transactions": {},
"comments": {},
"teams": {},
"organizations": {},
"items": {},
"products": {},
"payments": {},
"subscriptions": {},
"notifications": {},
"roles": {},
"groups": {},
"events": {},
"sessions": {},
"books": {},
"baskets": {},
"reviews": {},
"posts": {},
"articles": {},
"blogs": {},
"categories": {},
}
ResourceNouns are URL path segments that typically precede object identifiers.
var SensitiveResponseFields = map[string]struct{}{
"password_hash": {},
"password_digest": {},
"secret_key": {},
"private_key": {},
"api_secret": {},
"internal_id": {},
"ssn": {},
"social_security": {},
"credit_card": {},
"card_number": {},
"cvv": {},
"is_admin": {},
"isadmin": {},
"is_superuser": {},
"permissions": {},
"access_level": {},
}
SensitiveResponseFields are JSON field names in responses that indicate excessive data exposure.
Functions ¶
func BaselineLinksNeighbor ¶
BaselineLinksNeighbor reports whether the baseline response body already links to the neighbor request target — the page itself offers the neighbor as navigation (a "Next"/"Prev" pagination link, a sibling href, a catalog entry). A document never links to another user's *private* object as navigation, so a neighbor reachable straight from the page is intended public browsing, not a broken-authorization bypass.
This is the dominant IDOR false positive on blogs, documentation and product catalogs — e.g. GET /blog/3/ whose body contains href="/blog/4/" and href="/blog/2/", so probing the 2/4 neighbors merely re-fetches pages the site links to anyway.
neighborTarget is the neighbor request's path including any query string. It is only treated as a link signal when specific enough that an incidental short numeric substring cannot match: it must carry a query or a non-numeric path segment, so a bare "/4" does not match arbitrary digits in the body.
func ClassifyParamValue ¶
func ClassifyParamValue(value string) (IDType, Predictability, int)
ClassifyParamValue determines the type and predictability of an identifier value.
func ClassifyPathContext ¶
ClassifyPathContext checks if a value appears in a URL path immediately after a resource noun.
func ContainsEnforcementString ¶
ContainsEnforcementString checks if the first 4KB of a response body contains any soft-denial substring indicating authorization enforcement.
func GenerateNeighborIDs ¶
GenerateNeighborIDs produces candidate neighbor IDs for a given base value based on its detected IDType. Returns nil for unpredictable types (UUIDv4, Hex, Unknown).
func IsAuthChallengePage ¶
IsAuthChallengePage reports whether a response body is an authentication or single-sign-on page (a login form, an OAuth/OIDC/SAML challenge, or an authorization-denied notice) rather than a distinct application object.
IDOR/BOLA modules use this as a negative confirmation gate: a predicted identifier that merely returns the login page is not evidence of a predictable object reference. Every unauthenticated request to a protected endpoint returns the same login shell — only the per-request CSRF/session tokens differ — so a naive "200 + body differs from baseline" oracle fires on pure session-token noise (the Keycloak /openid-connect/auth false positive).
func IsLoginRedirect ¶
IsLoginRedirect checks if a response is a redirect to a login page.
func NormalizeName ¶
NormalizeName converts camelCase and kebab-case parameter names to lowercase snake_case.
func RequestCarriesCredential ¶
func RequestCarriesCredential(req *httpmsg.HttpRequest) bool
RequestCarriesCredential reports whether an HTTP request presents a user-identifying credential — an Authorization header, a Cookie, a well-known API-token header, or a credential query parameter.
IDOR / BOLA is by definition an *authorization* flaw: one principal reaching another principal's object. When the original request carries no credential there is no per-user authorization boundary to cross, so a neighbor id that returns "different but valid" content is most often just public, navigable content — a blog, a docs site, a product catalog — where distinct ids are *expected* to serve distinct pages (e.g. GET /blog/3/ vs /blog/4/). Modules use this to gate severity: without a credential the differential is a weak lead, not a High/Firm authorization bypass.
Types ¶
type AuthzVerdict ¶
type AuthzVerdict int
AuthzVerdict indicates whether authorization was enforced, bypassed, or uncertain.
const ( VerdictEnforced AuthzVerdict = iota // Access was denied VerdictBypassed // Access was granted (potential vulnerability) VerdictUncertain // Could not determine )
func (AuthzVerdict) String ¶
func (v AuthzVerdict) String() string
String returns a human-readable label for an AuthzVerdict.
type CompareOptions ¶
CompareOptions configures response comparison behavior.
func DefaultCompareOptions ¶
func DefaultCompareOptions() CompareOptions
DefaultCompareOptions returns sensible defaults for response comparison.
type IDClassification ¶
type IDClassification struct {
IsObjectID bool
IDType IDType
Predictability Predictability
NameSignal NameSignal
NameScore int
ValueScore int
PathScore int
TotalScore int
ResourceNoun string
}
IDClassification holds the full classification result for a parameter.
func ClassifyParam ¶
func ClassifyParam(name, value string, isPathParam bool, pathSegments []string) IDClassification
ClassifyParam performs full classification of a parameter as a potential object identifier.
type IDType ¶
type IDType int
IDType classifies the format of an identifier value.
const ( Unknown IDType = iota SequentialInt // 1, 42, 123456 ShortNumeric // 1-3 digit numbers (low predictability) StructuredCode // ORD-12345, INV-001-2 Base64Int // base64-encoded integer UUIDv1 // time-based UUID UUIDv4 // random UUID Hex // 16-64 character hex string Email // user@example.com Slug // human-readable-slug )
type NameSignal ¶
type NameSignal int
NameSignal indicates how strongly a parameter name suggests an object identifier.
const ( NoSignal NameSignal = 0 MediumSignal NameSignal = 2 HighSignal NameSignal = 3 )
func ClassifyParamName ¶
func ClassifyParamName(name string) (NameSignal, int)
ClassifyParamName evaluates whether a parameter name looks like an object identifier.
func (NameSignal) String ¶
func (s NameSignal) String() string
String returns a human-readable label for a NameSignal value.
type Predictability ¶
type Predictability int
Predictability indicates how easy it is to enumerate or guess an identifier.
const ( PredictNone Predictability = 0 PredictLow Predictability = 1 PredictMedium Predictability = 2 PredictHigh Predictability = 3 PredictVeryHigh Predictability = 4 )
func (Predictability) String ¶
func (p Predictability) String() string
String returns a human-readable label for a Predictability value.
type ResponseComparison ¶
type ResponseComparison struct {
StatusCodeMatch bool
BodyLengthDelta int
BodyLengthRatio float64
ContentIdentical bool
StructurallyIdentical bool
UserFieldsDiffer bool
DifferingFields []string
}
ResponseComparison holds the result of comparing two HTTP responses.
func CompareResponses ¶
func CompareResponses(baseline, probe *ResponseSummary, opts CompareOptions) *ResponseComparison
CompareResponses compares a baseline response against a probe response.
type ResponseSummary ¶
type ResponseSummary struct {
StatusCode int
BodyLength int
ContentType string
Body []byte
HasErrorMessage bool
}
ResponseSummary captures the key attributes of an HTTP response for comparison.
func SummarizeResponse ¶
func SummarizeResponse(statusCode int, contentType string, body []byte) *ResponseSummary
SummarizeResponse creates a ResponseSummary from raw response attributes.