Mobile, Cloud & DevOps Tools

GitHub Actions Workflow Visualizer

Paste a GitHub Actions workflow and see its triggers, job dependency graph from needs, matrix expansion, runners and steps, with checks for unpinned actions, broad permissions and risky pull_request_target use.

  • Job graph
  • Matrix expansion
  • Security and hygiene findings
Runs in your browser

Everything you paste, type or drop is processed in this browser tab. It is not uploaded, logged, stored or sent to analytics.

Actions workflow workspace

1 Your workflow

Examples:

Read with a safe YAML subset: anchors, aliases and custom tags are refused. Up to 1 MB.

Drop a .yaml, .yml or .json file, or (up to 1 MB).

2 Jobs, triggers and checks

Paste a workflow or load an example, then choose Visualise.

What the GitHub Actions Workflow Visualizer does

This visualiser reads a GitHub Actions workflow file and shows its triggers, the job dependency graph built from needs, every matrix combination the workflow will run, and the runners and steps of each job. It also checks the workflow against GitHub's security hardening guidance: actions not pinned to a commit SHA, missing or over-broad token permissions, risky pull_request_target use and untrusted text placed straight into shell scripts.

The file is parsed in your browser with a safe YAML reader. Nothing is run, and nothing is sent to GitHub or anywhere else.

How to use it

  1. Paste a workflow from .github/workflows, or drop the .yml file.
  2. Choose Visualise. The graph places jobs left to right in the order their needs allow them to run.
  3. Read the findings, most serious first. Problems are things that break the workflow or make it exploitable; warnings are risky choices; notes are worth knowing.
  4. Check the triggers and jobs tables, and the matrix tables to see exactly which combinations run after include and exclude.
  5. Download the graph as SVG or the analysis as JSON for a review.

Reading the results

The Runs column counts matrix jobs. A matrix built from an expression such as fromJSON(...) is only known at run time, so it is shown as not expanded rather than guessed.

Matrix expansion follows GitHub's documented rules: the product of the lists, then exclusions, then each include entry added to every combination it does not contradict, or appended as a new combination when it contradicts all of them.

Security findings come from patterns GitHub itself documents. They show where to look; they cannot prove a workflow is safe, and a finding may be acceptable in a private repository.

Worked example: a release workflow with two serious risks

The release example has four jobs in a chain - lint, build, publish, notify - triggered by version tags and by pull_request_target.

The lint job checks out github.event.pull_request.head.sha under pull_request_target, which runs a stranger's code with the repository's secrets and a write token, and it echoes ${{ github.event.pull_request.title }} directly inside a run script, so a pull request titled with a shell command would execute it. Both are reported as problems.

Warnings follow for the third-party action some-org/lint-action@v3 and the reusable workflow pinned to @main rather than a commit SHA, and for the missing top-level permissions block. Notes record that publish can write contents and id-token and that notify passes every secret with secrets: inherit.

Fixing script injection without losing the value

Expressions inside run are substituted into the script text before the shell sees it, so an issue title or branch name becomes code. The fix GitHub recommends is to pass the value through an environment variable - env: TITLE: ${{ github.event.pull_request.title }} - and refer to "$TITLE" in the script, where the shell treats it as data.

The visualiser only flags contexts GitHub names as attacker-controlled, such as titles, bodies, commit messages and head branch names. Values such as github.sha or matrix entries you define are not flagged.

Limitations: what the result does not prove

  • It reads one workflow file. Reusable workflows it calls, composite actions and the repository's default token settings are not fetched, so their risks are not assessed.
  • The YAML reader refuses anchors, aliases and custom tags, which GitHub also does not support in workflows.
  • It does not validate every key against GitHub's full schema or evaluate if: expressions; use actionlint in CI for exhaustive linting.

Privacy: where your data goes

Everything you paste, type or drop is processed in this browser tab. It is not uploaded, logged, stored or sent to analytics. Session recording and tag-manager scripts are switched off on this page.

Standards and sources

Frequently asked questions

Why should I pin GitHub Actions to a commit SHA?

A tag like v3 or a branch like main can be moved to point at different code, so a compromised or careless action author can change what your workflow runs. A full 40-character commit SHA cannot change. Pin third-party actions and note the version in a comment so updates stay readable.

What is wrong with pull_request_target?

It runs in the context of the base repository, with secrets and a token that can write, even for pull requests from forks. That is safe for labelling or commenting, but checking out and building the pull request's code in it hands those secrets to whoever wrote the pull request.

How do include and exclude change a matrix?

GitHub first builds every combination of the listed values and removes those matching an exclude entry. Each include entry is then added to every combination it does not contradict; if it contradicts all of them, it becomes a new combination. The matrix tables show the result.

What happens if a workflow has no permissions block?

The GITHUB_TOKEN receives the repository's or organisation's default permissions, which may be read and write for everything. Setting permissions: contents: read at the top and adding only what each job needs limits what a compromised step can do.

Why is a missing timeout-minutes worth a note?

Without it a job may run for up to 360 minutes. A hung test or deploy then holds a runner and uses minutes for six hours. A realistic timeout makes failures quick and cheap.

Does this run my workflow or contact GitHub?

No. The YAML is parsed and analysed in this browser tab only. To test a workflow for real, use a branch in your repository or a local runner tool.

Last reviewed by the A2Z.Tools team against the sources listed above.

Rate this tool

Was this tool useful? Your feedback helps us improve it.

No ratings yet — be the first to rate this tool.
Your rating (required)
0 / 2000

Please do not include passwords, payment details or other sensitive information.

Your feedback is sent privately to the A2Z.Tools team and will not be posted publicly.