pub enum FindingCategory {
Show 37 variants
AuthorityPropagation,
OverPrivilegedIdentity,
UnpinnedAction,
UntrustedWithAuthority,
ArtifactBoundaryCrossing,
FloatingImage,
LongLivedCredential,
PersistedCredential,
TriggerContextMismatch,
CrossWorkflowAuthorityChain,
AuthorityCycle,
UpliftWithoutAttestation,
SelfMutatingPipeline,
CheckoutSelfPrExposure,
VariableGroupInPrJob,
SelfHostedPoolPrHijack,
ServiceConnectionScopeMismatch,
TemplateExtendsUnpinnedBranch,
TemplateRepoRefIsFeatureBranch,
VmRemoteExecViaPipelineSecret,
ShortLivedSasInCommandLine,
SecretToInlineScriptEnvExport,
SecretMaterialisedToWorkspaceFile,
KeyVaultSecretToPlaintext,
TerraformAutoApproveInProd,
AddSpnWithInlineScript,
ParameterInterpolationIntoShell,
RuntimeScriptFetchedFromFloatingUrl,
PrTriggerWithFloatingActionRef,
UntrustedApiResponseToEnvSink,
PrBuildPushesImageWithFloatingCredentials,
SecretViaEnvGateToUntrustedConsumer,
NoWorkflowLevelPermissionsBlock,
ProdDeployJobNoEnvironmentGate,
LongLivedSecretWithoutOidcRecommendation,
PullRequestWorkflowInconsistentForkCheck,
GitlabDeployJobMissingProtectedBranchOnly,
// some variants omitted
}Expand description
MVP categories (1-5) are derivable from pipeline YAML alone. Stretch categories (6-9) need heuristics or metadata enrichment.
Variants§
AuthorityPropagation
OverPrivilegedIdentity
UnpinnedAction
UntrustedWithAuthority
ArtifactBoundaryCrossing
FloatingImage
LongLivedCredential
PersistedCredential
Credential written to disk by a step (e.g. persistCredentials: true on a checkout).
Disk-persisted credentials are accessible to all subsequent steps and any process
with filesystem access, unlike runtime-only HasAccessTo authority.
TriggerContextMismatch
Dangerous trigger type (pull_request_target / pr) combined with secret/identity access.
CrossWorkflowAuthorityChain
Authority (secret/identity) flows into an opaque external workflow via DelegatesTo.
AuthorityCycle
Circular DelegatesTo chain — workflow calls itself transitively.
UpliftWithoutAttestation
Privileged workflow (OIDC/broad identity) with no provenance attestation step.
SelfMutatingPipeline
Step writes to the environment gate ($GITHUB_ENV, pipeline variables) — authority can propagate.
CheckoutSelfPrExposure
PR-triggered pipeline checks out the repository — attacker-controlled fork code lands on the runner.
VariableGroupInPrJob
ADO variable group consumed by a PR-triggered job, crossing trust boundary.
SelfHostedPoolPrHijack
Self-hosted agent pool used in a PR-triggered job that also checks out the repository.
ServiceConnectionScopeMismatch
Broad-scope ADO service connection reachable from a PR-triggered job without OIDC.
TemplateExtendsUnpinnedBranch
ADO resources.repositories[] entry referenced by an extends:,
template: x@alias, or checkout: alias consumer resolves with no
ref: (default branch) or a mutable branch ref (refs/heads/<name>).
Whoever owns that branch can inject steps into the consuming pipeline.
TemplateRepoRefIsFeatureBranch
ADO resources.repositories[] entry pinned to a feature-class branch
(anything outside the main / master / release/* / hotfix/*
platform set). Feature branches typically have weaker push protection
than the trunk, so any developer with write access to that branch can
inject pipeline YAML that runs with the consumer’s authority. Strictly
stronger signal than template_extends_unpinned_branch — co-fires.
VmRemoteExecViaPipelineSecret
Pipeline step uses an Azure VM remote-exec primitive (Set-AzVMExtension / CustomScriptExtension, Invoke-AzVMRunCommand, az vm run-command, az vm extension set) where the executed command line interpolates a pipeline secret or a SAS token — pipeline-to-VM lateral movement primitive logged in plaintext to the VM and ARM.
ShortLivedSasInCommandLine
A SAS token freshly minted in-pipeline is interpolated into a CLI argument (commandToExecute / scriptArguments / –arguments / -ArgumentList) instead of passed via env var or stdin — argv ends up in /proc/*/cmdline, ETW, ARM status.
SecretToInlineScriptEnvExport
Pipeline secret value assigned to a shell variable inside an inline
script (export VAR=$(SECRET), $X = "$(SECRET)"). Once the value
transits a shell variable, ADO’s $(SECRET) log mask no longer
applies — transcripts (Start-Transcript, bash -x, terraform debug
logs) print the cleartext.
SecretMaterialisedToWorkspaceFile
Pipeline secret value written to a file under the agent workspace
($(System.DefaultWorkingDirectory), $(Build.SourcesDirectory),
or relative paths) without secureFile task or chmod 600. The file
persists in the agent workspace and is uploaded by
PublishPipelineArtifact and crawlable by later steps.
KeyVaultSecretToPlaintext
PowerShell pulls a Key Vault secret with -AsPlainText (or
ConvertFrom-SecureString -AsPlainText, or older
.SecretValueText syntax) into a non-SecureString variable. The
value never traverses the ADO variable-group boundary, so verbose
Az/PS logging and error stack traces print the credential.
Rule id is keyvault_secret_to_plaintext (single token “keyvault”)
rather than the snake_case derivation key_vault_… — matches the
docs filename and the convention used in the corpus evidence.
TerraformAutoApproveInProd
terraform apply -auto-approve against a production-named service connection
without an environment approval gate.
AddSpnWithInlineScript
AzureCLI@2 task with addSpnToEnvironment: true AND an inline script —
the script can launder federated SPN/OIDC tokens into pipeline variables.
ParameterInterpolationIntoShell
A type: string pipeline parameter (no values: allowlist) is interpolated
via ${{ parameters.X }} into an inline shell/PowerShell script body —
shell injection vector for anyone with “queue build”.
RuntimeScriptFetchedFromFloatingUrl
A run: block fetches a remote script from a mutable URL (refs/heads/,
/main/, /master/) and pipes it directly to a shell interpreter
(curl … | bash, wget … | sh, bash <(curl …), deno run https://…).
Whoever controls that URL’s content controls execution on the runner.
PrTriggerWithFloatingActionRef
Workflow trigger combines high-authority PR events
(pull_request_target, issue_comment, or workflow_run) with a step
whose uses: ref is a mutable branch/tag (not a 40-char SHA). Compromise
of the action’s default branch yields full repo write on the target repo.
UntrustedApiResponseToEnvSink
A workflow_run-triggered workflow captures a value from an external
API response (gh pr view, gh api, curl api.github.com) and writes
it into $GITHUB_ENV/$GITHUB_OUTPUT/$GITHUB_PATH without sanitisation.
A poisoned API field (branch name, title) injects environment variables
into every subsequent step in the same job.
PrBuildPushesImageWithFloatingCredentials
A pull_request-triggered workflow logs into a container registry via a
floating (non-SHA-pinned) login action. The compromised action receives
OIDC tokens or registry credentials, and the workflow then pushes a
PR-controlled image to a shared registry.
SecretViaEnvGateToUntrustedConsumer
First-party step writes a Secret/Identity-derived value into the
$GITHUB_ENV gate (or pipeline-variable equivalent) and a later
step in the same job that runs in Untrusted or ThirdParty trust
zone reads from the runner-managed env (${{ env.X }}). The two
component rules — self_mutating_pipeline (writer) and
untrusted_with_authority (consumer) — each see only half the
chain and emit no finding for the laundered consumer; this rule
closes the composition gap that R2 attack #3 exploited.
NoWorkflowLevelPermissionsBlock
Positive-invariant rule (GHA): the workflow declares neither a
top-level nor a per-job permissions: block, leaving GITHUB_TOKEN at
its broad platform default. Fires once per workflow file.
ProdDeployJobNoEnvironmentGate
Positive-invariant rule (ADO): a job referencing a production-named
service connection has no environment: binding, so it bypasses the
only ADO-side approval gate regardless of whether -auto-approve is
present. Strictly broader than terraform_auto_approve_in_prod.
LongLivedSecretWithoutOidcRecommendation
Positive-invariant rule (cross-platform): a long-lived static
credential is in scope but the workflow does not currently use any
OIDC identity even though the target cloud supports federation.
Advisory uplift on top of long_lived_credential that wires the
existing Recommendation::FederateIdentity variant.
PullRequestWorkflowInconsistentForkCheck
Positive-invariant rule (GHA): a PR-triggered workflow has multiple
privileged jobs where SOME have the standard fork-check if: and
OTHERS do not. Detects an intra-file inconsistency in defensive
posture — the org has the right instinct but applied it unevenly.
GitlabDeployJobMissingProtectedBranchOnly
Positive-invariant rule (GitLab): a job with a production-named
environment: binding has no rules: / only: clause restricting
it to protected branches. Deploy job runs (or attempts to run) on
every pipeline trigger.
Trait Implementations§
Source§impl Clone for FindingCategory
impl Clone for FindingCategory
Source§fn clone(&self) -> FindingCategory
fn clone(&self) -> FindingCategory
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for FindingCategory
impl Debug for FindingCategory
Source§impl<'de> Deserialize<'de> for FindingCategory
impl<'de> Deserialize<'de> for FindingCategory
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl Hash for FindingCategory
impl Hash for FindingCategory
Source§impl PartialEq for FindingCategory
impl PartialEq for FindingCategory
Source§impl Serialize for FindingCategory
impl Serialize for FindingCategory
impl Copy for FindingCategory
impl Eq for FindingCategory
impl StructuralPartialEq for FindingCategory
Auto Trait Implementations§
impl Freeze for FindingCategory
impl RefUnwindSafe for FindingCategory
impl Send for FindingCategory
impl Sync for FindingCategory
impl Unpin for FindingCategory
impl UnsafeUnpin for FindingCategory
impl UnwindSafe for FindingCategory
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.