- Secrets by name only. The config holds names; the provider holds values. The scanner checks the config and the generated YAML, and a finding never contains the matched value.
- Least privilege on GitHub.
permissions: contents: readby default,persist-credentials: falseon checkout. Actions default to major-version tags (actions/checkout@v4), which are mutable. Runslipway:pinto resolve them to commit SHAs, paste the result into thepinsdriver option, andstrictmode warns while any action is still unpinned. - No expression injection. GitHub expressions inside
runscripts are rejected. Secrets reach scripts only as stepenv, never interpolated into the command line. - Host keys are verified for SSH deploys; there is no “accept any host” mode. SSH runs in batch mode with connection timeouts, and the deploy key is removed from the runner when the script ends.
- Verified tooling on container providers. On Bitbucket and GitLab the Composer installer is checked against its published checksum before it runs. Node.js is installed from the official tarball on nodejs.org after it is checked against the published
SHASUMS256.txt. That protects against corrupt or tampered downloads; it is an integrity check, not a signature check. Use your own image through theimagedriver option if you need a fully pinned toolchain. - Validated inputs. Hosts, users, paths and URL paths are validated before they reach a shell script.
- Deterministic output makes review and drift detection reliable.
Concepts
Security model
Secrets by name, least privilege, verified hosts, and no expression injection in generated scripts.