Ansible Security Scanner: SAST for Playbooks, Roles, Collections
Static SAST scanner for Ansible playbooks, roles, collections, task files, vars, and inventories. Detects malicious code, RCE, command and template injection, hardcoded credentials, supply-chain risk, unauthorized cloud access, lateral movement, and reverse shells. Outputs SARIF, CycloneDX SBOM, GitLab SAST, JUnit, JSON, HTML, and Markdown reports with remediation guidance. Findings map to CWE, OWASP Top 10, OWASP ASVS, MITRE ATT&CK, NIST, and CIS. CI-native, autofix-capable, DevSecOps-ready.
1100 rules across 31 categories – all auto-discovered from YAML pattern plugins.
412 critical, 536 high, 132 medium, 19 low. Per-category breakdown on the dashboard.
Note
Scope. This is a static, pattern-based scanner - one layer in a defense-in-depth strategy. Pair it with the runtime controls you already trust (AAP/AWX approval gates, execution-environment lockdown, network egress policy, code review) for full coverage. See Limitations for the specific classes of issue this layer cannot catch on its own.
Contents
- Installation
- Quick Start
- What it detects
- Project Structure
- Documentation
- Requirements
- FAQ
- Contributing
- Security
- License & Attribution
Built with
Installation
Requires Python 3.11+. Installs an ansible-security-scanner command on your PATH.
Homebrew
Available via the cpeoples/homebrew-tap Homebrew tap.
pre-commit
Add to your .:
Two hook IDs are exposed:
ansible-security-scannerโ scans only the staged YAML /./j2 .files. Runs on every commit.cfg ansible-security-scanner-allโ scans the full repository tree. Wired to thepre-pushandmanualstages so it doesn’t fire on every commit; trigger it withpre-commit run –hook-stage pre-push ansible-security-scanner-allor in CI.
Quick Start
After installing, try one of these:
Smart defaults
- No
–formatgiven? If you pass–output report., the format is inferred from the extension (sarif .-> SARIF,sarif .-> JSON,json ./md .-> Markdown,markdown ./html .-> HTML,htm .-> XML,xml ./yml .-> YAML,yaml .-> CSV). An explicitcsv –formatalways wins; the scanner logs a warning if the two disagree so pipeline misconfigurations fail loudly. - No
–outputgiven with–output-per-file? Reports land under.(a self-documenting directory; add it to/security-reports/ .).gitignore –outputwould overwrite an input file? The scanner refuses and exits with code 2 - common footgun when running–files site.withyml –output site. yml .-as-format inference.yml
Working from a source checkout? Use python main. instead of the
installed CLI - it’s a thin shim around the same entry point.
What it detects
The scanner ships 1100 rules across 31 auto-discovered categories. Highlights:
Malicious code and post-exploitation
- Reverse shells, webshell deployment, system compromise, lateral movement
- Anti-forensics, obfuscation and evasion, tunneling, offensive tooling
Code execution and injection
- Command injection, template injection, variable injection
- Jinja lookup RCE, dangerous Ansible modules, binary planting
Secrets and supply chain
- Hardcoded credentials and API keys
- Supply-chain risk (Galaxy collections, ad-hoc downloads, untrusted URLs)
- Data exfiltration, webhook exposure, external URL contact
Cloud, IaC, and platform hardening
- Unauthorized cloud access, Kubernetes insecure specs
- Privilege escalation, unsafe permissions, environment hijacking
- Insecure communication (TLS, SSH, plaintext protocols)
AI/ML and operational hygiene
- AI/ML supply-chain and prompt-injection risks
- Ansible hygiene, Ansible-specific anti-patterns, operational security
Every rule includes severity, framework mappings (CWE, OWASP Top 10, OWASP ASVS, MITRE ATT&CK, NIST, CIS Controls), vulnerable and remediated examples, and remediation guidance. Findings are deduplicated across files via cross-file taint tracking. See the rule dashboard for a per-category, per-severity breakdown.
Project Structure
Documentation
The long-form documentation is split by topic. Each page is a standalone
Markdown file in docs/ - GitHub renders them inline, and the
Hugo site at GitHub Pages serves the same content
with a navigation sidebar and search.
| Topic | Source |
|---|---|
| CLI flags, exit codes, suppressions, cross-file dedup | docs/cli. |
Environment variables (auth, defaults, –changed-files) | docs/environment. |
| Programmatic Python API | docs/api. |
| Output formats (Markdown, JSON, SARIF, GL-SAST, SBOM, …) | docs/output-formats. |
| Allowlist / suppressing findings | docs/allowlist. |
| CI/CD integration (GitLab CI, GitHub Actions) | docs/ci-cd. |
| MR / PR comments (auto-detected, self-hosted-aware) | docs/mr-pr-comments. |
| Adding custom patterns | docs/custom-patterns. |
| Security score model | docs/scoring. |
| Testing | docs/testing. |
| Limitations of static analysis | docs/limitations. |
| Releasing | docs/releasing. |
Documentation site
Full documentation is auto-generated from the docs/ Markdown
files plus the pattern YAML plugins, and published via Hugo + GitHub
Pages on every push to main.
The build pipeline (.) runs:
build_- copies eachdocs. py docs/into Hugo’s. md content/with appropriate front-matter, and generates one rule-table page per pattern category.- Hugo builds a static site with the Relearn theme.
- The site is deployed to GitHub Pages.
To preview locally:
Requirements
- Python 3.11+
- PyYAML >= 6.0
- Jinja2 >= 3.0
- httpx >= 0.27 (used by
–github-comment/–gitlab-commentonly)
For development work from source:
FAQ
What does Ansible Security Scanner scan?
Ansible playbooks, roles, collections, task files, vars, and inventories. It detects malicious code, RCE, command and template injection, hardcoded credentials, supply-chain risk, unauthorized cloud access, lateral movement, and reverse shells.
How is this different from ansible-lint?
ansible-lint focuses on style and best practices. Ansible Security Scanner
is a SAST tool focused on security signals: dataflow taint tracking,
supply-chain risk, secrets, and known attack patterns mapped to OWASP, CWE,
NIST, CIS, and MITRE ATT&CK.
Does it run in CI/CD?
Yes. It outputs SARIF, CycloneDX SBOM, GitLab SAST, JUnit, JSON, HTML, and Markdown. GitHub Actions, GitLab CI, and Jenkins are all supported, and PR/MR comments can be posted automatically.
Is it free to use?
Yes. Ansible Security Scanner is Apache-2.0 licensed and free to use commercially.
Contributing
See CONTRIBUTING. for the full dev-environment
walkthrough, pattern-authoring guide, and PR checklist.
TL;DR for a first-time clone:
Common contribution paths:
- Add a security pattern - drop a YAML plugin in
src/ansible_(auto-discovered at startup). See ยง3 ofsecurity_ scanner/patterns/ CONTRIBUTING.for the schema and validation steps.md - Add a remediation generator - create a module in
src/ansible_, then wire it intosecurity_ scanner/remediations/ remediation_.generator. py - Add an output formatter - subclass
base.underBaseFormatter src/ansible_and register it insecurity_ scanner/formatters/ utils..get_ formatter_ class - Run the gates before opening a PR -
python task.(full suite),py test python task.,py lint python task..py build
Security
This repository runs three GitHub-native security checks on every push and pull request:
- Dependabot (
.) - weekly update PRs forgithub/dependabot. yml pipandgithub-actionsecosystems, plus out-of-band security advisories. - CodeQL (default setup, configured in repo settings) - SAST against
the Python in
src/ansible_.security_ scanner/ - Secret scanning + push protection - alerts on credential-shaped strings in tracked files.
Why some paths are excluded from secret scanning
Because this is a security scanner, the repo ships two structurally required corpora that look exactly like real secrets:
- Hand-curated negative fixtures (
tests/playbooks/bad_andexample. yml tests/playbooks/multi_) - the integration tests feed these to the scanner to assert each rule class fires correctly. They contain deliberate hardcoded credentials, fake AWS keys, and embedded SQS URLs; nothing here is a real credential.example_ bad/** - Pattern-pack
vulnerable_blocks (examples: src/ansible_) - rule definitions document, by design, the literal strings each rule is meant to match. These blocks are rendered into the generated rule docs that ship at https://cpeoples.github.io/ansible-security-scanner/.security_ scanner/patterns/**
Both surfaces are excluded via .,
where each entry is annotated with the structural reason it’s there.
Privacy
The scanner runs locally and does not phone home. There is no
telemetry, no analytics, no usage pings, and no remote rule fetch.
Comment posting is the only outbound network call, and it only
fires when you pass –mr-comment (or the equivalent) with an
explicit token; the target host is the GitLab or GitHub instance
you point it at.
Reporting a vulnerability
Open a private security advisory via the Security tab rather than a public issue. Vulnerabilities in the scanner itself (e.g. a code path that lets an attacker leak unredacted secrets through an MR comment) are in scope; vulnerabilities in Ansible playbooks detected by the scanner are not - those belong to the playbook’s maintainer.
License & Attribution
This project is licensed under the Apache License, Version 2.0.
If you use, fork, embed, or build on this project, please retain attribution
to the original repository and contributors. The NOTICE file at
the repo root spells out exactly what is required.
In plain English:
- You can use this scanner commercially, modify it, embed it in larger tools, or build a paid product on top of it - no fee, no permission needed.
- You must keep the
LICENSEandNOTICEfiles in any redistribution. - If you fork this project or ship a derivative work (for example, a rebranded scanner, a hosted service, or a SaaS wrapper), you must state that it is derived from Ansible Security Scanner by Chris Peoples and link back to the original repository: https://github.com/cpeoples/ansible-security-scanner.
- The project name “Ansible Security Scanner” /
ansible-security-scanneris a reserved mark of the original author (Apache-2.0 ยง6). Your fork is welcome - under a different name. - Apache-2.0 includes an explicit patent grant and a retaliation clause: if you sue the project or its contributors over a patent related to the software, your rights under the license terminate automatically.
See NOTICE for the full attribution terms and
LICENSE for the Apache-2.0 text.
AI-assistance disclosure
This project follows the Ansible community AI policy. LLM tooling has helped with scaffolding, refactoring, test generation, and documentation. All of it is reviewed, edited, and tested by a human before being committed. The rules, threat models, and design decisions are mine, and every PR runs the full test, lint, and security gate before merge.