Code ScanningRules

Analysis Mode

Use xgrep's built-in native analyzers via mode: analysis rules.

Analysis Mode

Some checks are too context-dependent to express as a pattern. "Is this imported name ever used?", "does this self.x read refer to an attribute the class never defines?", "is this regex vulnerable to ReDoS?" — answering these accurately needs whole-file or semantic analysis, not text/AST shape matching. xgrep ships these as native analyzers, dispatched with mode: analysis.

A pattern rule that tries to approximate one of these checks is almost always a false-positive factory; the native analyzer is the precise implementation.

Writing an analysis-mode rule

Set mode: analysis and name an analyzer with analyzer:. The rule carries no pattern — the analyzer produces all findings:

rules:
  - id: my-undefined-attribute-rule
    languages: [python]
    severity: ERROR
    message: Attribute is never defined on the class; this raises AttributeError.
    mode: analysis
    analyzer: undefined-attribute
    metadata:
      category: correctness

Rules of the mode (enforced at load time, mirroring how mode: taint forbids pattern):

  • analyzer: is required and must name a known analyzer — an unknown name is a load error, not a silent no-op.
  • A pattern clause (pattern, pattern-regex, pattern-either, …) is not allowed alongside mode: analysis. Writing analyzer: alone implies mode: analysis.
  • languages: still scopes which files the rule runs on; each analyzer is also internally gated to the language(s) it supports.

Built-in analyzers

analyzer:LanguagesDetects
unused-importpythonImported names never referenced in the file.
unreachable-codepythonStatements after a return/raise/break/continue in the same suite.
go-unreachable-codegoStatements after a return/break/continue/goto/panic in the same statement list. A terminator inside an if/for/switch branch does not make the code after that branch dead, and a labelled statement stays reachable because a goto can jump to it.
go-no-effectgoA call statement whose result is discarded and whose callee, declared in the same file, does nothing else — the value-receiver mistake, where t.addDays(7) should be t = t.addDays(7). A callee that returns nothing, can panic, or is not declared in this file is never flagged.
non-callablepythonA call whose callee is provably not callable.
no-effectpythonA bare comparison/arithmetic statement whose result is discarded.
inconsistent-returnpythonA function that returns a value on some paths and None/implicitly on others.
conflicting-signaturepythonA method overriding a local base method with an incompatible arity.
equality-typespython==/!= between operands of known incompatible types (b"x" == "x").
wrong-arg-constructorpythonA constructor / self-method call with an argument count __init__ cannot accept.
wrong-arg-callpythonA module-function call with an incompatible positional-argument count.
first-param-not-selfpythonAn instance method whose first parameter is not self.
invalid-escapepythonA non-raw string/bytes literal with an unrecognized backslash escape ("\d").
undefined-attributepythonA self.x read where x is never defined on the class or a local base.
use-before-defpythonA local variable read on a path where it is never bound first (UnboundLocalError).
empty-exceptpythonA try whose except handler body is a single pass, silently swallowing the error (CWE-390).
redundant-comparisonpythonA comparison made constant by a preceding elif/guard over the same operands (CWE-570).
redos-staticpythonA re.* call whose string-literal pattern has catastrophic-backtracking (ReDoS) shape (CWE-1333).
duplicate-bindingjavascript, typescriptA name bound twice in one parameter list or destructuring pattern.
duplicate-propertyjavascriptAn object literal that declares the same data-property key more than once.
duplicate-var-decljavascriptA var name declared more than once in the same function scope.
javascript-unused-variablejavascript, typescript, tsxA variable declared with an initializer and never referenced in its scope.
use-of-returnless-functionjavascriptThe result of a function that never returns a value is used (always undefined).
prototype-pollutionjavascript, typescriptA for…in / Object.keys() copy into an object without prototype-key guards.
incomplete-url-schemejavascript, typescriptA scheme allowlist recognizing some but not all of javascript:/data:/vbscript:.
incomplete-url-substringjavascript, typescriptA substring hostname check not anchored to the URL's host.
incomplete-html-sanitizationjavascript, typescriptA .replace() chain missing some attribute-breaking characters.
unsafe-cert-trustjavaTLS endpoint identification disabled or never enabled.
expose-representationjavaA public method returns a private array/Map field by reference, or stores a parameter straight into one.
java-compare-identicaljavaA comparison whose two operands are the identical value (x == x), always constant — a likely copy-paste bug.
java-confusing-method-namejavaA class declaring public boolean equals(SameType) — a confusing overload of equals(Object), never invoked by standard callers.
java-control-charsjavaA string/char literal containing a literal control or zero-width character instead of an explicit escape.
java-equals-arrayjavaequals()/hashCode() called on an ARRAY receiver, which compares/hashes identity rather than contents — use java.util.Arrays (CWE-595).
java-inner-class-could-be-staticjavaA non-static nested class whose body never uses the enclosing instance, so the implicit outer reference is pure overhead (CWE-1070).
java-pointless-forwardingjavaA one-parameter method whose whole body forwards that parameter (plus one more argument) to another method — removable indirection.
java-self-assignmentjavaA plain assignment whose two sides are the identical expression (x = x) — a no-op, likely a missing this. qualifier.
implicit-pending-intentjavaA mutable implicit PendingIntent reaching a broadcast/activity sink (CWE-927).
sensitive-broadcastjavaSensitive data broadcast in Intent extras without a permission (CWE-927).
insecure-basic-authjavaA Basic auth header sent after a plaintext http:// URL (CWE-522).
lock-orderjavaInconsistent lock acquisition order across methods (deadlock, CWE-833).
type-narrowingjavaA compound assignment narrowing a wider type (int += long, CWE-190).
ruby-incomplete-sanitizationrubyA .sub/.sub! that removes only the first occurrence of a metacharacter.
javascript-asi-hazardjavascriptA statement that ends without its semicolon in a file that otherwise uses them — at least 90% of the file's terminable statements do — so automatic semicolon insertion decides where the statement ends (CWE-670). A file written without semicolons is silent entirely, and a trailing comment folded into the statement node is looked past so the report lands where the semicolon belongs.
javascript-misleading-indentationjavascriptA statement indented to the body column of a preceding brace-less if/else/while/for, so it reads as a second body statement but always runs (CWE-483). A braced body, a follower at the control statement's own column, a body not indented past its control statement, and do … while are all silent.
javascript-missing-this-qualifierjavascript, typescriptA bare identifier inside a class method that names one of that class's own members — a field, a method, or a this.X = … target — so the reference reaches a global or an outer binding instead of the member (CWE-682). A name bound anywhere in the file, a standard global, a call to the enclosing method itself, and constructor are all silent.
javascript-property-write-on-primitivejavascriptA property or index WRITE whose receiver is provably a primitive: a literal ((0).foo = 42), or a local the file binds only to primitive literals. The write is silently discarded (CWE-704). A null/undefined receiver throws rather than no-opping and belongs to a different rule; parameters, uninitialised locals, and any name assigned more than once are silent.
nodejs-cyclic-importjavascript, typescript, tsxA require/import whose resolved target can reach back to the importing file through the project's resolved module edges — a circular dependency — rather than every require indiscriminately.
nodejs-unresolvable-importjavascript, typescript, tsxA relative import that resolves to no scanned file, or a bare import that is neither a Node builtin nor a declared dependency (only when the project has a package.json) — a module that will not resolve at runtime.
nodejs-dubious-importjavascript, typescript, tsxA subpath import that reaches past a dependency's declared public interface (its package.json exports) into an internal file Node would refuse to resolve.
nodejs-missing-exportsjavascript, typescript, tsxA named import (import { x } / const { x } = require) of a binding the target module — statically enumerable — does not export.
ruby-dead-store-of-localrubyA local variable assigned a value that the immediately following statement overwrites without reading it (CWE-563). Both statements must be plain name = expr assignments to the same local and the overwriting right-hand side must never mention the name, so an accumulator (x = x + 1, s = s.upcase), a conditional overwrite (x = 2 if c), an x += 1 operator assignment, a non-local target (@ivar, CONST, h[:k], obj.attr =), a multiple assignment, and any variable an enclosing rescue/ensure mentions all stay silent.
swift-cleartext-logging-string-writeswiftA sensitive value written into a String (print/debugPrint/dump(SENSITIVE, to: &s), s.write(SENSITIVE), SENSITIVE.write(to: &s)) that is later console-logged bare (print/debugPrint/dump(s) with no to: redirect) — indirect cleartext logging (CWE-312/532). A string that only received harmless data, or a sensitive write into a string that is never bare-logged, stays silent.
go-integer-overflow-conversiongoA strconv parse result narrowed to a smaller fixed-width integer type without a bounds check, where the value is not used as a size or index — a correctness smell (CWE-190/681, audit).
go-integer-overflow-conversion-sinkgoA strconv parse result narrowed without a bounds check whose value reaches a make size, a slice index, or a slice bound — an undersized allocation or out-of-range index from attacker input (CWE-190/681).
go-ssh-auth-bypassgoAn ssh.ServerConfig auth callback whose body always returns a nil error, accepting every client (CWE-287).
go-slice-boundsgoA constant index/slice bound that provably exceeds a slice's known length/capacity, panicking at runtime (CWE-125).
go-dead-storegoAn assignment to a local variable whose value is never read before being overwritten or returned, via backward liveness (CWE-563).
csharp-dead-storecsharpAn assignment to a local variable whose value is never read before being overwritten or the scope exits, via backward liveness (CWE-563).
csharp-unused-labelcsharpA labeled statement whose name is never named by a goto in the same method/function scope, dead code (CWE-561).
csharp-null-derefcsharpA dereference of a local flow-sensitively bound to null (T x = null; … x.M) with no intervening null guard or reassignment (CWE-476).
csharp-self-assignmentcsharpA no-op assignment whose left- and right-hand sides are the identical lvalue (x = x, obj.P = obj.P), CWE-480/-561.
csharp-nested-loop-shared-varcsharpA nested for-loop that mutates a loop variable declared by an enclosing for-loop, clobbering the outer counter (CWE-670/-682).
csharp-stringbuilder-char-initcsharpA StringBuilder constructed with a character-literal argument, which binds to the int-capacity overload instead of setting content (CWE-704).
csharp-redundant-tostringcsharpA no-argument .ToString() used as an operand of string concatenation, where + already converts it (CWE-561).
csharp-int-get-hash-codecsharpA GetHashCode() call on a provably small-int receiver (default(int) / (int) cast of int/short/ushort/byte/sbyte), whose hash is the value itself — a useless call (CWE-561).
csharp-hashed-but-no-hashcsharpthis used as a key/element of a hash-based collection (Dictionary/HashSet/Hashtable/ConcurrentDictionary) inside a type that overrides exactly one of Equals/GetHashCode — a silent lookup-failure bug (CWE-697).
csharp-dead-binding-storecsharpA binding that introduces a local never read in its scope: an is/case declaration-pattern variable, or a using-statement resource variable, whose value is discarded (CWE-563).
csharp-futile-conditional-empty-ifcsharpAn if with an else clause whose then-branch AND else-branch are both empty (an empty block or ;, with no comment trivia) — the whole conditional is a no-op (CWE-561).
c-buffer-boundsc, cppA copy/write whose constant byte length provably exceeds a fixed-size destination buffer's known capacity, an out-of-bounds write (CWE-787/121/122).
c-oversized-readc, cppA byte-oriented read (read/pread/recv/recvfrom/fgets/fread) whose CONSTANT byte length provably exceeds the known capacity of a fixed-size local destination buffer — a stack/heap array, or a constant-sized malloc/calloc/alloca/new[] pointer not since reassigned — so external input overruns it (CWE-120/CWE-787); the safe sizeof(dst)-bounded idiom (length == capacity) and any non-constant length are not flagged.
c-free-not-on-heapc, cppA free()/delete of a pointer provably bound to non-heap storage — a stack array, alloca, &local, or string literal (CWE-590).
c-mismatched-freec, cppA deallocation whose routine does not match the allocation — free() of a C++ new/new[] pointer, or delete/delete[] mismatching new[]/new/malloc (CWE-762).
c-uninitialized-varc, cppA read of a local scalar/pointer variable declared with no initializer and never written before the read (CWE-457).
c-improper-initc, cppA read of a fixed-size char/wchar_t array whose contents were never initialized — the buffer (or a pointer aliased onto it) reaches a string-read sink (strcat/strncat/strlen/printLine…) with no earlier memset/strcpy/element-write/&escape initializing it (CWE-665); the aggregate companion to c-uninitialized-var.
c-memory-leakc, cppA heap allocation stored in a local pointer that reaches function exit never freed, returned, stored, or handed to an unknown callee (CWE-401).
c-explicit-null-derefc, cppA dereference of a local pointer provably bound to a NULL constant (int *p = NULL; … *p), the explicit-NULL half of CWE-476 that taint cannot source.
c-interproc-uafc, cppA use-after-free where an in-file helper unconditionally frees a pointer parameter — a C++ reference-to-pointer (void f(T *&p){ … free(p); }) or a by-value pointer (void f(T *p){ … free(p); }) — and the caller then dereferences the dangling pointer (CWE-416).
c-unchecked-return-valuec, cppA call to a fallible libc function (scanf/fscanf/sscanf/fread/fgets/rename/remove/system/setuid…) whose return value is discarded — the call is a bare expression statement — so a failure or short read goes undetected (CWE-252).
c-incorrect-return-value-checkc, cppA return-value check that cannot detect failure: a pointer-returning call (fgets/fopen/strchr…) in an ordered comparison with 0, or a size_t-returning call (fread/fwrite/strlen…) compared < 0 (always false) (CWE-253).
c-sizeof-pointer-typec, cppA sizeof(p) on a local pointer used as an allocation/copy size — malloc(sizeof(p)) / memset(buf, 0, sizeof(p)) — which sizes by the pointer width, not the pointed-to object (CWE-467).
c-assignment-in-conditionc, cppAn if/while/do condition that is directly an assignment (if (x = 5)) rather than a comparison — a likely == typo; the deliberate forms if ((x = 5)) / while ((c = f()) != EOF) are not flagged (CWE-481).
c-comparison-no-effectc, cppA bare ==/!= comparison used as an expression statement (x == 5;) whose result is discarded — a no-effect statement likely meant to be an assignment (CWE-482).
c-empty-return-nonvoidc, cppA return; with no value in a function whose declared return type is not void, so the caller reads an indeterminate value (CWE-758).
c-return-stack-addressc, cppA function returning a local array (which decays to a pointer into the frame) or the address of a non-static local (return &x;) — a dangling pointer once the frame is torn down (CWE-562).
c-switch-missing-defaultc, cppA switch statement with no default: label, so an unhandled value passes silently (CWE-478).
c-switch-fallthroughc, cppA non-empty switch case that does not end in break/return/goto/continue/throw and is followed by another label — an omitted break (CWE-484); empty stacked labels are not flagged.
cpp-catch-genericcppA catch(...) or catch(std::exception&) that swallows every exception where specific handling was intended (CWE-396).
cpp-throw-genericcppA function declared throw(std::exception) or a throw of a bare std::exception object, rather than a specific type (CWE-397).
cpp-xxe-unconfigured-parsercppA locally-constructed Xerces parser that reaches parse() with no hardening call dominating the parse (setDisableDefaultEntityResolution(true) on every path, following reference aliases) and no other interaction — default entity resolution left enabled (CWE-611).
c-fixed-address-pointerc, cppA pointer set to a hard-coded numeric address (char *p = (char *)0x400000;) — not a real object, so a dereference is undefined behavior (CWE-587).
c-empty-error-handlerc, cppAn if that tests errno but whose body is empty — the error is detected and then ignored (CWE-390).
c-suspicious-commentc, cppA comment containing a developer-marker keyword (TODO/FIXME/HACK/BUG/XXX/KLUDGE/LATER) — an in-code admission of unfinished or known-broken work (CWE-546).
c-heap-inspectionc, cppA heap buffer holding a password — read via fgets/fgetws and authenticated via LogonUser* — released by free/realloc/HeapFree without a prior memset/SecureZeroMemory/ZeroMemory clear, leaving the plaintext in freed heap memory (CWE-244).
c-unlock-not-lockedc, cppA lock release/unlock call (stdThreadLockRelease/pthread_mutex_unlock/LeaveCriticalSection/ReleaseSRWLock*) on a lock with no prior acquire of the same lock earlier in the function — released before ever locked (CWE-832).
c-missing-fd-releasec, cppA file descriptor or OS handle opened into a local (fopen/open/CreateFile family) that reaches function exit never closed, returned, stored, or passed to any callee — the descriptor/handle leaks (CWE-775, ref CWE-773).
c-lock-not-releasedc, cppA mutex acquired by a lock-acquire call (pthread_mutex_lock/EnterCriticalSection/AcquireSRWLock*/stdThreadLockAcquire) that reaches function exit still held — no unlock, pthread_cond_wait, or handoff of the same lock appears later in the function (CWE-667). A caller-passed lock parameter (acquired on the caller's behalf) is not flagged.
c-missing-crypto-stepc, cppA Windows CryptoAPI encryption pipeline (gated by CryptAcquireContext) that omits a required step, leaving a consumer using an uninitialized handle: CryptHashData on a hash never CryptCreateHash'd, CryptDeriveKey from a hash never CryptHashData'd, or CryptEncrypt/CryptDecrypt with a key no producer (CryptDeriveKey/CryptGenKey/CryptImportKey) ever created (CWE-325).
cpp-dangling-string-cstrcppA pointer into a temporary std::string's buffer — .c_str()/.data() on a std::string(...)/to_string(...) temporary — stored in a variable, assignment, or return, so it dangles once the temporary is destroyed at the end of the full expression (CWE-416); a call argument or immediate subscript (which do not outlive the statement) is not flagged.
c-strncpy-flipped-argsc, cppA bounded string copy/concat (strncpy/wcsncpy/strncat/wcsncat) whose count argument is derived from the SOURCE operand — sizeof(src), a strlen/wcslen-family call on src, or the source identifier itself (possibly + arithmetic) — instead of the destination's capacity, so a source longer than the destination overflows it (CWE-119/CWE-787); a count that references the destination (sizeof(dst), min(strlen(src), sizeof(dst)-1)) or a constant count is not flagged.
cpp-uniqueptr-uafcppA pointer or address into a std::unique_ptr's object used after the object is destroyed (CWE-416): the receiver is a make_unique(...)/std::unique_ptr<T>(...) temporary — or a call to a same-file function whose by-value return type is unique_ptr — whose .get(), &*, &(->member), or reference-bound *temp escapes into a variable/assignment/return; or a named unique_ptr is unconditionally reset(...)/reassigned between a .get() borrow and a later raw->/*raw/raw[i] dereference. A value copy, a call-argument consumption, a reference-returning receiver, a rebind, a use before the reset, an address-of, and passing the pointer to a call all stay silent.
cpp-iterator-invalidationcppAn iterator, element pointer, or element reference into a std::vector/std::string that outlives the container's storage (CWE-416). Two shapes: (1) a handle into a locally-declared container (v.begin()/v.data()/&v[i]/T& r = v[i]) used after an unconditional invalidating call on it (push_back/emplace_back/insert/erase/resize/reserve/clear/assign, or a string append/+=), with no re-binding in between; (2) a reference/handle into an ELEMENT of a temporary container (temp[i]/temp.at(i), where temp is a by-value container return or constructor) that escapes via a range-for, an auto&&/T& reference binding, or a reference-returning return. A use before the mutation, a re-bind after it, a conditional mutation, a parameter container, a handle passed to a function, iterating a whole temporary, or a by-value copy of an element is not flagged.
cpp-istream-fixed-buffercppAn unbounded C++ istream operator>> extraction into a fixed-size char/wchar_t array (std::cin >> buf; where char buf[N]) — a gets()-class read that writes an arbitrary-length token past the array with no bound (CWE-676/CWE-120). Fires only when the base of the >> chain is a known istream (cin/wcin, or an istream-typed local) and the extraction is unbounded; a std::setw-width-limited chain, a std::string target, a scalar or single-char lvalue, and a bare pointer are all left silent.
solidity-reentrancysolidityA contract state variable written after an external ether-transfer call, with no reentrancy guard, violating checks-effects-interactions (SWC-107).
dataflow-taintjava, python, php, kotlin, scala, lua, go, csharp, rust, swift, c, cpp, javascript, typescriptSource→sink taint via the unified dataflow engine.
regex-hostname-dotanyAn unescaped . in a hostname regex.
regex-unanchored-hostnameanyA hostname regex lacking start/end anchors.
regex-semi-anchoredanyAn anchor (^/$) that binds only one alternation branch (^a|b).
regex-useless-escapeanyUnnecessary backslash escapes in a regex.
regex-unbound-backrefanyA regex backreference to a capturing group that does not exist — \1 with no group 1, or \k<name> naming an undefined group.
regex-backref-before-groupanyA regex backreference that appears before the group it targets is defined — a forward reference that only matches the empty string. A backref inside a lookbehind is excluded.
regex-backref-into-neg-lookaheadanyA regex backreference to a group defined inside a negative lookahead, referenced from outside it — a negative lookahead never captures, so it only matches the empty string.
regex-backspace-escapeanyA \b escape inside a character class, where it means the backspace character (U+0008) rather than a word boundary — almost always a mistake.
regex-malformedjavascript, typescript, tsxA pattern that is invalid in every ECMAScript mode and throws a SyntaxError when compiled: an unclosed group or character class, a quantifier with nothing to repeat, stacked quantifiers, or bounds written in the wrong order ({3,2}). Only RegExp(…) arguments are analyzed, where a bad pattern is a runtime failure; a malformed regex literal is a syntax error the file cannot survive. Patterns that are invalid only under the u flag (\!x, a{1, a]b) are not flagged, because the flag is not visible from the pattern and they are valid literals without it.
regex-duplicate-char-in-classanyA character class that lists the same character twice, by evaluated code point — under any spelling ([??], [\x0a\x0a], [:|\\|]) — which is redundant and has no effect. A character merely inside a range is not a duplicate; classes using u/v-flag syntax (\u{…}, \p{…}, &&, --) are not analyzed.
regex-always-matchesanyA regex used in .test()/.search() that always matches because it can match the empty string on a universally-reachable path (optional/starred content, reachable at ^, $, or anywhere). A both-ends-anchored empty, a \b assertion, a universal wildcard .*, and a $-only optional under .search are not flagged.
regex-bad-tag-filteranyA regex HTML/XML tag filter that can be bypassed.
regex-unmatchable-caretanyA ^ in a position where it can never match.
regex-unmatchable-dollaranyA $ in a position where it can never match.
regex-suspicious-rangeanyA suspicious character range in a […] class (cross-case, digit-to-letter).
regex-suspicious-characteranyA suspicious escape such as \a (bell) or \b (backspace) in a regex.
gha-env-laundered-injectionyamlAn untrusted GitHub Actions context stored in an env: variable and then written to a $GITHUB_ENV/$GITHUB_OUTPUT/$GITHUB_PATH environment file.
gha-run-shell-injectionyamlAn untrusted GitHub Actions context stored in an env: variable and then re-evaluated as shell code (eval, sh -c/bash -c, command position, or command substitution $( … )/backticks) in a run: step.
gha-script-injectionyamlAn untrusted GitHub Actions context laundered through an env: var, read inside an embedded script through the interpreter's environment API (python os.environ, node process.env, Ruby ENV[…], Perl $ENV{…}, PHP getenv/$_ENV) and reaching a code-execution sink there (os.system, eval, subprocess(shell=True), child_process.exec, Ruby/Perl single-string system/exec and backticks/qx, PHP shell_exec/passthru/proc_open). The multi-argument argv form, which runs no shell, stays silent.
gha-github-script-injectionyamlAn untrusted GitHub Actions context interpolated into an actions/github-script script: input, spliced into and executed as JavaScript.
gha-cross-job-injectionyamlAn attacker-controlled job output — set directly, or indirectly from a steps.<id>.outputs.* write of an arbitrary/laundered value — consumed as needs.<job>.outputs.<name> in a downstream run: step.
gha-command-injectionyamlAn untrusted GitHub Actions context interpolated into a run: shell command, a shell-argument action input (subcommand:/args:), or an input a curated third-party action executes as a script (Amadevus/pwsh-script script:, mikefarah/yq cmd:, addnab/docker-run-action run:/options:, …), via the workflow IR (no YAML-sibling scoping bug). Matrix dimensions the job builds from an untrusted value resolve to arbitrary, so ${{ matrix.x }} from a dynamic matrix fires.
gha-composite-action-injectionyamlA caller-controlled inputs.* value (or another attacker-controlled context) interpolated into a run: shell command inside a composite action.yml/action.yaml, across the caller/action boundary.
gha-env-var-injectionyamlAn arbitrary GitHub Actions context written to $GITHUB_ENV (or ::set-env), injecting an environment variable that hijacks a later step.
gha-env-path-injectionyamlAn arbitrary GitHub Actions context written to $GITHUB_PATH, prepending an attacker-controlled directory to PATH.
gha-output-clobberingyamlAn arbitrary GitHub Actions context written to $GITHUB_OUTPUT (or ::set-output), clobbering a step output a later step trusts.
gha-ssrf-request-forgeryyamlAn arbitrary GitHub Actions context reaching the request route/URL input of an HTTP-request action (e.g. octokit/request-action route:), letting an attacker control the request target (SSRF).
gha-cache-poisoningyamlA build cache reachable across the trust boundary: a release/publishing workflow using a cache-aware step (incl. implicit setup-* caching), or a job that both checks out untrusted PR code and caches — so a poisoned cache entry can be shipped or planted.
gha-reusable-workflow-injectionyamlA caller-controlled inputs.* value of a reusable workflow (on: workflow_call) interpolated into a run: shell command. Review-grade MEDIUM on its own; promoted to HIGH (CRITICAL under a privileged external trigger) when a same-repo caller is found passing an attacker-controlled context to that input.
gha-argument-injectionyamlAn untrusted GitHub Actions value reaching the program argument of a text-processing tool — a sed expression or an awk program — where the argument is executed as a program (GNU sed's e command, awk's system()) rather than passed as data. Sources are the laundered lane: an env:-bound arbitrary context, the runner-provided GITHUB_HEAD_REF, or git metadata read back inside the script ($(git log --format=%s)). A tainted file operand, here-string or awk -v assignment is data and stays silent.
gha-secret-in-logyamlA secret (${{ secrets.* }} bound to an env: var) transformed by a masking-defeating operation (base64/jq/cut/tr/rev/xxd/substring/…) and then printed with echo/printf. GitHub masks the raw secret in logs, but the transformed value is not masked, so it leaks into the build log.

The any-language regex analyzers are scoped by the rule's own languages: field and adapt to the language internally (for example, Ruby hostname anchors are \A/\z rather than ^/$).

Configuration

Analysis-mode rules take no parameters in metadata. When an analyzer needs to vary, it does so by analyzer identity (the regex kinds are separate analyzer: names rather than a kind option) or by intrinsic behaviour. A future structured options: block is the planned home for any genuinely rule-configurable value.

See also

On this page