Write type-inferred taint rules for Go code. The SDK ships with 29 pre-defined QueryType classes in codepathfinder.go_rule covering stdlib and popular frameworks, plus metadata for 33 additional classes documented in the SDK reference. The @go_rule decorator scopes analysis to Go files.
Every Go rule file starts with these imports:
from codepathfinder.go_decorators import go_rule
from codepathfinder.go_rule import (
GoGinContext, GoGormDB, GoStrconv,
# ... browse the FQN browser for the full list
)
from codepathfinder import flows
from codepathfinder.presets import PropagationPresetsBrowse all 70+ pre-defined classes in the Go SDK reference or the FQN browser.
Declares a Go-scoped rule. The decorator automatically injects language="go" into the generated IR, so analysis stays within .go files.
@go_rule(
id="GO-GORM-SQLI-001", # required
name="", # auto-generated from function name if empty
severity="MEDIUM", # CRITICAL | HIGH | MEDIUM | LOW | INFO
category="security",
cwe="",
cve="",
tags="",
message="", # defaults to "Security issue detected by {id}"
owasp="",
)
def detect_gorm_sqli():
return flows(...)idrequirednameseveritycategorycwecvetagsmessageowaspBase class for type-inferred matchers. Subclass it to describe a Go type; the engine resolves the fully-qualified name of each call site and matches against fqns. Wrong FQN → 0 findings (this is the primary precision tool).
from codepathfinder import QueryType
class GoHTTPClient(QueryType):
fqns = ["net/http.Client"] # FQNs (prefix match)
patterns = ["*http.Client"] # pattern fallbacks with * and ?
match_subclasses = True # match types that embed/implement this (default True)fqnspatternsmatch_subclassesfqns to garbage (e.g., "xxx"). If findings drop to 0, type inference is working. If findings persist, the engine fell through to patterns, so fix your FQN.Selects one or more methods on a QueryType. Returns a MethodMatcher that supports .where(), .arg(), and .tracks().
# Single method
GoHTTPClient.method("Do")
# Multiple methods (OR semantics; any one triggers)
GoGinContext.method("Query", "Param", "PostForm", "GetHeader")
# Chained with precision modifiers
GoOSExec.method("Command").where(0, regex(r"^sh$|^bash$")).tracks(1)Raises ValueError if called with no method names. Defined at codepathfinder/query_type.py:156-172.
Matches attribute / field access on a typed receiver (as opposed to method calls). Returns an AttributeMethodMatcher. This matcher is terminal and cannot be chained with .where() / .tracks().
# HTTP request body / URL are attributes, not method calls
GoHTTPRequest.attr("Body", "URL.Path", "URL.RawQuery")Filters matches by argument value. .arg() is an exact alias for .where().
from codepathfinder import lt, regex, missing
# Positional argument (index 0)
GoOSExec.method("Command").where(0, "sh")
GoOSExec.method("Command").where(0, regex(r"^sh$|^bash$"))
# Keyword-style argument by name
GoHTTPClient.method("Get").where("url", regex(r"^http://"))
# Numeric qualifier
SomeClass.method("MakeKey").where("bits", lt(2048))
# Absent argument (missing keyword)
SomeResponse.method("SetCookie").where("Secure", missing())position_or_namerequiredconstraintPins taint to specific parameters. On sinks, only taint reaching a tracked parameter produces a finding. On sources, only the tracked return value / parameter is marked tainted. This is the single highest-impact precision tool, so use it on every sink.
# Sink: only alert if taint reaches the first positional arg
GoGormDB.method("Raw").tracks(0)
# Source: track the return value
GoOSEnv.method("Getenv").tracks("return")
# Multiple positions (OR semantics)
CursorLike.method("execute").tracks(0, "query")Accepts int (positional), str (keyword), or the literal string "return".
The codepathfinder.go_rule module exports 29 QueryType classes for the Go standard library and popular frameworks. Each has verified FQNs and annotated method roles (source, sink, or sanitizer).
GoHTTPRequest, GoSQLDB, GoOS, GoOSExec, GoFmt, GoIO, GoFilepath, GoStrconv, GoJSON, GoTemplate, GoContext, GoCrypto, ...GoGinContext, GoEchoContext, GoFiberCtx, GoGorillaMuxRouter, GoChiRouterGoGormDB, GoPgxConn, GoSqlxDB, GoRedisClient, GoMongoCollectionGoJWTToken, GoGRPCServerTransportStream, GoViperConfig, GoYAMLDecoderGoHTTPClient, GoRestyClientReal rule from the code-pathfinder registry (GO-GORM-SQLI-001). Detects user input from Gin / Echo / Fiber / Chi / net/http flowing into GORM's Raw() or Exec().
"""GO-GORM-SQLI-001: SQL injection via GORM Raw/Exec with user-controlled input."""
from codepathfinder.go_rule import (
GoGinContext,
GoEchoContext,
GoFiberCtx,
GoGormDB,
GoHTTPRequest,
GoStrconv,
QueryType,
)
from codepathfinder import flows
from codepathfinder.presets import PropagationPresets
from codepathfinder.go_decorators import go_rule
class GoChiRouter(QueryType):
fqns = ["github.com/go-chi/chi/v5"]
patterns = ["chi.*"]
match_subclasses = False
@go_rule(
id="GO-GORM-SQLI-001",
severity="CRITICAL",
cwe="CWE-89",
owasp="A03:2021",
tags="go,security,sql-injection,gorm,CWE-89,OWASP-A03",
message=(
"User-controlled input flows into GORM Raw() or Exec() with raw SQL. "
"Use parameterized queries: db.Raw('SELECT * WHERE name = ?', name)"
),
)
def detect_gorm_sqli():
return flows(
from_sources=[
GoGinContext.method(
"Query", "Param", "PostForm", "GetHeader",
"ShouldBindJSON", "BindJSON", "GetRawData",
),
GoEchoContext.method("QueryParam", "FormValue", "Param", "PathParam"),
GoFiberCtx.method("Params", "Query", "FormValue", "Get"),
GoHTTPRequest.method("FormValue", "PostFormValue"),
GoHTTPRequest.attr("Body", "URL.Path", "URL.RawQuery"),
],
to_sinks=[
GoGormDB.method("Raw", "Exec"),
],
sanitized_by=[
GoStrconv.method("Atoi", "ParseInt", "ParseFloat", "ParseUint"),
],
propagates_through=PropagationPresets.standard(),
scope="global",
)