--- description: Usage tips and recipes for running zizmor locally and in CI/CD. --- # Usage ## Input collection Before auditing, `zizmor` performs an input collection phase. There are three input sources that `zizmor` knows about: 1. Individual workflow and composite action files, e.g. `foo.yml` and `my-action/action.yml`; 2. "Local" GitHub repositories in the form of a directory, e.g. `my-repo/`; 3. "Remote" GitHub repositories in the form of a "slug", e.g. `pypa/sampleproject`. !!! tip By default, a remote repository will be audited from the `HEAD` of the default branch. To control this, you can append a `git` reference to the slug: ```bash # audit at HEAD on the default branch zizmor example/example # audit at branch or tag `v1` zizmor example/example@v1 # audit at a specific SHA zizmor example/example@abababab... ``` !!! tip Remote auditing requires Internet access and a GitHub API token. See [Operating Modes](#operating-modes) and [GitHub API token permissions](#github-api-token-permissions) for more information. `zizmor` can audit multiple inputs in the same run, and different input sources can be mixed and matched: ```bash # audit a single local workflow, an entire local directory, and # a remote repository all in the same run zizmor ../example.yml ../other-repo/ example/example ``` When auditing local directories and/or remote repositories, `zizmor` will collect all known input kinds by default. To configure collection behavior, you can use the `--collect=...` option. ```bash # collect everything regardless of `.gitignore` patterns zizmor --collect=all example/example # collect everything while respecting `.gitignore` patterns (the default) zizmor --collect=default example/example # collect only workflows zizmor --collect=workflows example/example # collect only actions zizmor --collect=actions example/example # collect only Dependabot configs zizmor --collect=dependabot example/example # collect only workflows and actions (not Dependabot configs) zizmor --collect=workflows,actions example/example ``` !!! warning "Deprecation" `--collect=workflows-only` and `--collect=actions-only` are deprecated aliases for `--collect=workflows` and `--collect=actions`, respectively, as of `v1.15.0`. Users should switch to the non-deprecated forms, as the deprecated forms will be removed in a future release. !!! tip `--collect=all` can be significantly slower than `--collect=default`, particularly when collecting from directories that contain large hierarchies of paths that would be ignored by `.gitignore` patterns. !!! tip `--collect=...` only controls input collection from repository input sources. In other words, `zizmor --collect=actions workflow.yml` *will* audit `workflow.yml`, since it was passed explicitly and not collected indirectly. By default, `zizmor` will warn (but not fail) if it fails to parse an input file. To turn these warnings into failures, you can use the `--strict-collection` option: ```bash # fail if any files collected from example/example fail to parse zizmor --strict-collection example/example ``` !!! important `--strict-collection` is available in `v1.7.0` and later. ## Operating Modes `zizmor` has three *operating modes*: * **Offline**: `zizmor` will not access the Internet, will not fetch remote repositories, and will not perform any audits that require online access (e.g. to the GitHub API). * **Online**: `zizmor` will fetch remote repositories as necessary, and will perform all audits that require online access. * **Online sans audits**: `zizmor` will fetch remote repositories as necessary, but will skip any audits that require online access. `zizmor` attempts to select a default operating mode based on the user's environment: - If `ZIZMOR_OFFLINE` is set, then `zizmor` runs in offline mode. - If `GH_TOKEN` is set, then `zizmor` runs in online mode with audits. - Additionally `ZIZMOR_NO_ONLINE_AUDITS` is set, then `zizmor` runs online sans audits. - If neither `ZIZMOR_OFFLINE` nor `GH_TOKEN` are set, then `zizmor` runs in offline mode. Or, as a flowchart: ```mermaid flowchart TD B{ZIZMOR_OFFLINE set?} -- Yes --> C[Offline mode] B -- No --> D{GH_TOKEN set?} D -- No --> C D -- Yes --> E{ZIZMOR_NO_ONLINE_AUDITS set?} E -- Yes --> F[Online sans audits mode] E -- No --> G[Online mode] ``` Each operating mode can also be made explicit through command-line flags: ```bash # force offline, even if a GH_TOKEN is present # this disables all online actions, including repository fetches zizmor --offline workflow.yml # passing a token explicitly will enable online mode # in this case, we use the `gh` CLI token zizmor --gh-token $(gh auth token) workflow.yml # online for the purpose of fetching the input (example/example), # but all audits themselves are offline zizmor --no-online-audits --gh-token $(gh auth token) example/example ``` ### GitHub API token permissions !!! tip If you're running `zizmor` locally with an online mode, it is **strongly recommended** that you use `gh auth token` from the [GitHub CLI] to automatically access an API token and avoid error-prone manual provisioning. This token is almost always pre-configured with sufficient permissions, meaning that you **do not** need any of the manual steps below. [GitHub CLI]: https://cli.github.com/ When running in an online mode, `zizmor` uses the GitHub API for various operations, including fetching a repository's contents (for the collection phase) and fetching tag/branch/commit histories (for the auditing phase). Generally speaking, `zizmor` does **not** require any special permissions from its GitHub API token: it uses the token *primarily* to provide authentication for rate-limited API requests. However, if you are auditing a private remote repository (e.g. `zizmor myorg/private-repo`) or auditing _any_ input that contains private references (e.g. `#!yaml uses: myorg/private-action`), then you may need to provision permissions for the token: - `#!yaml contents: read` for GitHub Actions - `repo` for OAuth tokens and "classic" PATs - An appropriate repository access scope for fine-grained PATs In addition to these permissions, some integrations of `zizmor` (like GitHub Advanced Security) may require additional permissions in the context of GitHub Actions. See [Integration - GitHub Actions](./integrations.md#github-actions) for more details. ## Output formats `zizmor` always produces output on `stdout`. ### Cargo-style output ("plain") By default, `zizmor` produces `cargo`-style diagnostic output. ```console error[template-injection]: code injection via template expansion --> ./tests/integration/test-data/template-injection/pr-425-backstop/action.yml:28:7 | 28 | - name: case4 | ^^^^^^^^^^^ this step 29 | uses: azure/powershell 30 | with: 31 | inlineScript: Get-AzVM -ResourceGroupName "${{ inputs.expandme }}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inputs.expandme may expand into attacker-controllable code | = note: audit confidence → Low ``` This output will be colorized by default when sent to a supporting terminal and uncolorized by default when piped to another program. Users can also explicitly disable output colorization by setting `NO_COLOR=1` in their environment. This format can also be explicitly selected with `--format=plain`. #### Color customization When invoked from a terminal, `zizmor` will attempt to enrich its output with ANSI colors. !!! note `--color` is available in `v1.5.0` and later. Some users may prefer to explicitly enable or disable this behavior. For example, GitHub Actions is not a terminal but it does support ANSI colors, so enabling colors in GitHub Actions can make logs more readable. To explicitly control `zizmor`'s colorization behavior, use the `--color` option: ```bash # force colorization zizmor --color=always ... # force no colorization zizmor --color=never ... ``` `zizmor` also respects various environment variables for colorization: * [`NO_COLOR`](https://no-color.org/): if set to any value, disables colorization * [`FORCE_COLOR`](https://force-color.org/): if set to any value, enables colorization * [`CLICOLOR_FORCE`](https://bixense.com/clicolors/): if set to any value, enables colorization ### JSON !!! important The JSON format is versioned, and `--format=json` is an alias for the current version. The current version of the JSON format is `v1`. You can use `--format=json-v1` to explicitly select the current version. The following compatibility policy is used for JSON format versions: 1. The current version of the format is always aliased as `json`. 2. When a new version of the JSON format is added, `--format=json` will show a deprecation warning, and will transition to the new version with the next major release. 3. When a new version of the JSON format is added, explicit uses of the old version will show a deprecation warning. 4. The old version will be removed in the *subsequent* major release (i.e., the major release after the one that transitions the `json` alias). !!! important `--format=json-v1` is available in `v1.6.0` and later. !!! important `--format=json-v1` uses 0-based line numbering, where line numbers are denoted by the key `row`. This is as opposed to `--format=plain` and `--format=SARIF`, where line numbers are 1-based. With `--format=json`, `zizmor` will produce a flat array of findings in JSON format: ```bash zizmor --format=json . | jq .[0] ``` ??? Example "Example output" ```json { "ident": "github-env", "desc": "dangerous use of environment file", "url": "https://docs.zizmor.sh/audits/#github-env", "determinations": { "confidence": "Low", "severity": "High", "persona": "Regular" }, "locations": [ { "symbolic": { "key": { "Local": { "prefix": ".", "given_path": "./tests/integration/test-data/github-env/action.yml" } }, "annotation": "write to GITHUB_ENV may allow code execution", "route": { "components": [ { "Key": "runs" }, { "Key": "steps" }, { "Index": 0 }, { "Key": "run" } ] }, "kind": "Primary" }, "concrete": { "location": { "start_point": { "row": 9, "column": 6 }, "end_point": { "row": 10, "column": 40 }, "offset_span": { "start": 202, "end": 249 } }, "feature": " run: |\n echo \"foo=$(bar)\" >> $GITHUB_ENV", "comments": [] } } ], "ignored": false } ``` ### SARIF `zizmor` supports SARIF via `--format=sarif`. SARIF is a JSON-based standard for representing static analysis results. See [Integration - GitHub Actions](./integrations.md#github-actions) for information on using `zizmor` with GitHub's Advanced Security functionality via GitHub Actions. ### GitHub Annotations !!! note `--format=github` is available in `v1.6.0` and later. `zizmor` supports GitHub annotations via `--format=github`. See [Workflow Commands for GitHub Actions] for additional information about annotations. [Workflow Commands for GitHub Actions]: https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands !!! warning GitHub annotations come with significant limitations: a single CI step can only render 10 annotations at a time. If your `zizmor` run produces more than 10 findings, only the first 10 will be rendered; all subsequent findings will be logged in the actions log but **will not be rendered** as annotations. See orgs/community?26680 and orgs/community?68471 for additional information. ## Exit codes `zizmor` will exit with a variety of exit codes, depending on how you invoke it and what happens during the run. In general: | Code | Meaning | | ---- | ------- | | 0 | Successful audit; no findings to report (or SARIF mode enabled). | | 1 | Error during audit; consult output. | | 2 | Argument parsing failure; consult output. | | 11 | One or more findings found; highest finding is "informational" level. | | 12 | One or more findings found; highest finding is "low" level. | | 13 | One or more findings found; highest finding is "medium" level. | | 14 | One or more findings found; highest finding is "high" level. | All other exit codes are currently reserved. !!! warning "Removal" Versions of zizmor prior to `v1.14.0` used exit code `10` to indicate the highest finding having "unknown" severity. This exit code is no longer used as of `v1.14.0`. Beyond this general table, the following modes of operation also change the exit code behavior: * If you run with `--no-exit-codes`, `zizmor` will **not** use exit codes 11 and above. * If you use `--format=sarif`, `zizmor` will **not** use exit codes 11 and above. !!! tip "Why?" Because SARIF consumers generally don't expect SARIF producers (like `zizmor`) to exit with a non-zero code *except* in the case of an internal failure. SARIF consumers expect semantic results to be communicated within the SARIF itself. * If you run with `--fix` *and* all findings are successfully auto-fixed, `zizmor` will **not** use exit codes 11 and above. !!! tip "Why?" Because the higher exit codes indicate that action needs to be taken, but a successful application of all fixes means that no action is required. ## Using personas !!! tip `--persona=...` is available in `v0.7.0` and later. `zizmor` comes with three pre-defined "personas," which dictate how sensitive `zizmor`'s analyses are: * The _regular persona_: the user wants high-signal, low-noise, actionable security findings. This persona is best for ordinary local use as well as use in most CI/CD setups, which is why it's the default. !!! note This persona can be made explicit with `--persona=regular`, although this is not required. * The _pedantic persona_, enabled with `--persona=pedantic`: the user wants *code smells* in addition to regular, actionable security findings. This persona is ideal for finding things that are a good idea to clean up or resolve, but are likely not immediately actionable security findings (or are actionable, but suggest a intentional security decision by the workflow/action author). For example, using the pedantic persona will flag the following with an `unpinned-uses` finding, since it uses a symbolic reference as its pin instead of a hashed pin: ```yaml uses: actions/checkout@v3 ``` produces: ```console $ zizmor --pedantic tests/test-data/unpinned-uses.yml help[unpinned-uses]: unpinned action reference --> tests/test-data/unpinned-uses.yml:14:9 | 14 | - uses: actions/checkout@v3 | ------------------------- help: action is not pinned to a hash ref | = note: audit confidence → High ``` !!! tip This persona can also be enabled with `--pedantic`, which is an alias for `--persona=pedantic`. * The _auditor persona_, enabled with `--persona=auditor`: the user wants *everything* flagged by `zizmor`, including findings that are likely to be false positives. This persona is ideal for security auditors and code reviewers, who want to go through `zizmor`'s findings manually with a fine-toothed comb. !!! tip Some audits, notably [`self-hosted-runner`](./audits.md#self-hosted-runner), *only* produce auditor-level results. This is because these audits require runtime context that `zizmor` lacks access to by design, meaning that their results are always subject to false positives. For example, with the default persona: ```console $ zizmor self-hosted.yml 🌈 completed self-hosted.yml No findings to report. Good job! (1 suppressed) ``` and with `--persona=auditor`: ```console $ zizmor --persona=auditor self-hosted.yml warning[self-hosted-runner]: runs on a self-hosted runner --> self-hosted.yml:13:5 | 13 | runs-on: [self-hosted, my-ubuntu-box] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ self-hosted runner used here | = note: audit confidence → High 1 finding: 0 informational, 0 low, 1 medium, 0 high ``` ## Auto-fixing results { #auto-fixing-results } !!! tip `--fix=[MODE]` is available in `v1.10.0` and later, and is considered stable as of `v1.15.0`. Starting with `v1.10.0`, `zizmor` can automatically fix a subset of its findings. Auto-fixable findings are marked with an additional `note:` annotation beneath their body, e.g.: ```console hl_lines="10" error[template-injection]: code injection via template expansion --> example.yml:18:36 | 17 | - run: | | ^^^ this run block 18 | echo "doing a thing: ${{ inputs.test }}" | ^^^^^^^^^^^ may expand into attacker-controllable code | = note: audit confidence → High = note: this finding has an auto-fix ``` To attempt auto-fixes for *safe* fixes, you can use the `--fix` or `--fix=safe` option: ```bash # these two are equivalent zizmor --fix example.yml zizmor --fix=safe example.yml ``` ### Unsafe fixes !!! important Unsafe fixes **must** be manually reviewed for semantic correctness. By default, `--fix` will only apply *safe* fixes, i.e. fixes that are safe to apply with minimal human oversight due to their low breakage risk. Not all changes are safe, however, and `zizmor` offers *unsafe* fixes for some findings as well. These fixes are *often* correct, but require human review. To apply *unsafe* fixes, you can either use `--fix=all` (to enable both safe and unsafe fixes) or `--fix=unsafe-only` (to enable only unsafe fixes): ```bash zizmor --fix=all example.yml zizmor --fix=unsafe-only example.yml ``` ### Limitations `zizmor`'s auto-fix mode has several limitations that are important to keep in mind: * **In-place modification**: `--fix=[MODE]` modifies fixable inputs in-place, meaning that the original files will be modified. * **No remote fixes**: as a corollary to the above, `--fix=[MODE]` does not support remote inputs (e.g. `zizmor example/example`). * **Format preservation**: `--fix=[MODE]` attempts to preserve the original format of the input files, including exact indentation and comments. However, this is ultimately a heuristic, and some patches may not match the file's exact style. ## Filtering results There are two straightforward ways to filter `zizmor`'s results: 1. If all you need is severity or confidence filtering (e.g. "I want only medium-severity and/or medium-confidence and above results"), then you can use the `--min-severity` and `--min-confidence` flags: !!! tip `--min-severity` and `--min-confidence` are available in `v0.6.0` and later. !!! warning "Deprecation" `--min-severity=unknown` and `--min-confidence=unknown` are **deprecated** as of `v1.14.0` and will be removed in a future release. Users should omit these entirely, as they were no-ops even prior to deprecation. ```bash # filter informational, and low findings with low confidence zizmor --min-severity=medium --min-confidence=medium ... ``` 2. If you need more advanced filtering (with nontrivial conditions or state considerations), then consider using `--format=json` and using `jq` (or a script) to perform your filtering. As a starting point, here's how you can use `jq` to filter `zizmor`'s JSON output to only results that are marked as "high confidence": ```bash zizmor --format=json-v1 ... | jq 'map(select(.determinations.confidence == "High"))' ``` ## Ignoring results `zizmor`'s defaults are not always 100% right for every possible use case. If you find that `zizmor` produces findings that aren't right for you (and **aren't** false positives, which should be reported!), then you can choose to *selectively ignore* results via either special ignore comments *or* a `zizmor.yml` configuration file. ### With comments !!! note Ignore comment support was added in `v0.6.0`. Findings can be ignored inline with `# zizmor: ignore[rulename]` comments. This is ideal for one-off ignores, where a whole `zizmor.yml` configuration file would be too heavyweight. Multiple different audits can be ignored with a single comment by separating each rule with a comma, e.g. `# zizmor: ignore[artipacked,ref-confusion]`. To ignore a single `template-injection` finding: ```yaml title="example.yml" run: | # zizmor: ignore[template-injection] echo "${{ github.event.issue.title }}" ``` Ignore comments can also have a trailing explanation: ```yaml title="example.yml" run: | # zizmor: ignore[template-injection] i promise this is safe echo "${{ github.event.issue.title }}" ``` !!! important An ignore comment can be placed anywhere in any span identified by a finding, **so long** as it can be identified as a YAML comment. In particular, this means that you **can't** place an ignore comment in the middle of a string or a block literal. For example, the following does not work: ```yaml title="example.yml" # this is not suppressed, since the comment is actually part of the string run: | echo "${{ github.event.issue.title }}" # zizmor: ignore[template-injection] ``` To fix this, you should place the ignore comment outside of the string, e.g. directly above it: ```yaml title="example.yml" run: | # zizmor: ignore[template-injection] echo "${{ github.event.issue.title }}" ``` ### With `zizmor.yml` When ignoring multiple findings (or entire files), a `zizmor.yml` configuration file is easier to maintain than one-off comments. Here's what a `zizmor.yml` file might look like: ```yaml title="zizmor.yml" rules: template-injection: ignore: - safe.yml - somewhat-safe.yml:123 - one-exact-spot.yml:123:456 ``` Concretely, this `zizmor.yml` configuration declares three ignore rules, all for the [`template-injection`](./audits.md#template-injection) audit: 1. Ignore all findings in `safe.yml`, regardless of line/column location 2. Ignore *any* findings in `somewhat-safe.yml` that occur on line 123 3. Ignore *one* finding in `one-exact-spot.yml` that occurs on line 123, column 456 More generally, the filename ignore syntax is `workflow.yml:line:col`, where `line` and `col` are both optional and 1-based (meaning `foo.yml:1:1` is the start of the file, not `foo.yml:0:0`). To pass a configuration to `zizmor`, you can either place `zizmor.yml` somewhere where `zizmor` [will discover it], or pass it explicitly via the `--config` argument. With `--config`, the file can be named anything: ```bash zizmor --config my-zizmor-config.yml /dir/to/audit ``` !!! important When using `--config`, only a single configuration file is used (instead of potentially discovering multiple configuration files, one per input source). As a result, using `--config` is **generally not recommended** unless auditing a single input source (file, directory, or remote repository). !!! tip Starting with `v1.8.0`, you can use the `ZIZMOR_CONFIG` environment variable to specify a configuration file. `ZIZMOR_CONFIG=my-config.yml` is equivalent to `--config my-config.yml`. [will discover it]: ./configuration.md#discovery See [Configuration: `rules..ignore`](./configuration.md#rulesidignore) for more details on writing ignore rules. ## Caching between runs !!! tip Persistent caching (between runs of `zizmor`) is available in `v0.10.0` and later. !!! warning Caches can contain sensitive metadata, especially when auditing private repositories! Think twice before sharing your cache or reusing it across machine/visibility boundaries. `zizmor` caches HTTP responses from GitHub's REST APIs to speed up individual audits. This HTTP cache is persisted and re-used between runs as well. By default `zizmor` will cache to an appropriate user-level caching directory: * Linux and macOS: `$XDG_CACHE_DIR` (`~/.cache/zizmor` by default) * Windows: `~\AppData\Roaming\woodruffw\zizmor`. To override the default caching directory, pass `--cache-dir`: ```bash # cache in /tmp instead zizmor --cache-dir /tmp/zizmor ... ``` ## Other GitHub hosts !!! warning Support for custom GitHub Enterprise instances is provided on a **best-effort** basis. If you're a corporate user of `zizmor` who is interested in improving `zizmor`'s GitHub Enterprise support, please [let us know](https://github.com/zizmorcore/zizmor/issues/new) and [consider sponsoring](./index.md#sponsoring) development in this area! `zizmor` supports GitHub instances other than `github.com`. To use it with your [GitHub Enterprise](https://github.com/enterprise) instance (either cloud or self-hosted), pass your instance's domain with `--gh-hostname` or `GH_HOST`: ```bash zizmor --gh-hostname custom.example.com ... # or, with GH_HOST GH_HOST=custom.ghe.com zizmor ... ``` ## Limitations `zizmor` can help you write more secure GitHub workflow and action definitions, as well as help you find exploitable bugs in existing definitions. However, like all tools, `zizmor` is **not a panacea**, and has fundamental limitations that must be kept in mind. This page documents some of those limitations. ### `zizmor` is a _static_ analysis tool { #static-analysis } `zizmor` is a _static_ analysis tool. It never executes any code, nor does it have access to any runtime state. In contrast, GitHub Actions workflow and action definitions are highly dynamic, and can be influenced by inputs that can only be inspected at runtime. For example, here is a workflow where a job's matrix is generated at runtime by a previous job, making the matrix impossible to analyze statically: ```yaml build-matrix: name: Build the matrix runs-on: ubuntu-latest outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - id: set-matrix run: | echo "matrix=$(python generate_matrix.py)" >> "${GITHUB_OUTPUT}" run: name: ${{ matrix.name }} needs: - build-matrix runs-on: ubuntu-latest strategy: matrix: ${{ fromJson(needs.build-matrix.outputs.matrix) }} steps: - run: | echo "hello ${{ matrix.something }}" ``` In the above, the expansion of `${{ matrix.something }}` is entirely controlled by the output of `generate_matrix.py`, which is only known at runtime. In such cases, `zizmor` will err on the side of verbosity. For example, the [template-injection](./audits.md#template-injection) audit will flag `${{ matrix.something }}` as a potential code injection risk, since it can't infer anything about what `matrix.something` might expand to. ### `zizmor` audits workflow and action _definitions_ only { #definitions-only } `zizmor` audits workflow and action _definitions_ only. That means the contents of `foo.yml` (for your workflow definitions) or `action.yml` (for your composite action definitions). In practice, this means that `zizmor` does **not** analyze other files referenced by workflow and action definitions. For example: ```yaml example: runs-on: ubuntu-latest steps: - name: step-1 run: | echo foo=$(bar) >> $GITHUB_ENV - name: step-2 run: | # some-script.sh contains the same code as step-1 ./some-script.sh ``` `zizmor` can analyze `step-1` above, because the code it executes is present within the workflow definition itself. It *cannot* analyze `step-2` beyond the presence of a script execution, since it doesn't audit shell scripts or any other kind of files. More generally, `zizmor` cannot analyze files indirectly referenced within workflow/action definitions, as they may not actually exist until runtime. For example, `some-script.sh` above may have been generated or downloaded outside of any repository-tracked state. ### YAML anchors stymie analysis { #yaml-anchors } !!! tip "TL;DR" `zizmor`'s support for YAML anchors is provided on a **best effort** basis. Users of `zizmor` are **strongly encouraged** to avoid anchors if they care about accurate static analysis results. `zizmor` tries very hard to present *useful* source spans in its audit results. To do this, `zizmor` needs to know a lot of about the inner workings of the YAML serialization format that GitHub Actions workflows, action definitions, and Dependabot files are expressed in. YAML is a complicated serialization format, but GitHub *mostly* uses a tractable subset of it. One conspicuous exception to this is [YAML anchors](https://yaml.org/spec/1.2.2/#3222-anchors-and-aliases), which GitHub has [decided to support](https://github.blog/changelog/2025-09-18-actions-yaml-anchors-and-non-public-workflow-templates/) in workflow and action definitions as of September 2025. Anchors make `zizmor`'s analysis job *much* harder, as they introduce a layer of (arbitrarily deep) indirection and misalignment between the deserialized object model (which is what `zizmor` analyzes) and the source representation (which `zizmor` spans back to). As a result, `zizmor`'s support for YAML anchors is **best effort only**. Users are **strongly encouraged** to avoid anchors in their workflows and actions. Bug reports for issues in inputs containing anchors are appreciated, but will be given a lower priority relative to bugs that aren't observed with YAML anchors. If you're having issues with inputs containing anchors, see [Troubleshooting - Failures on inputs containing YAML anchors] for some suggested workarounds. [Troubleshooting - Failures on inputs containing YAML anchors]: ./troubleshooting.md#failures-on-inputs-containing-yaml-anchors