When should a Checkov exemption be an inline skip comment rather than a config-file skip-check or skip-path?
answer
- compare blast radius, then visibility
- one block versus the whole scan
- a path skip drops every check there
- config skips pre-approve future violations
- fixtures and examples are the honest path case
basics
~20 sAn inline skip fits one resource that legitimately violates one check: narrow, and visible in the diff. Use skip-check or skip-path only when the rule or path is wrong for the whole scan, since both are invisible at the violating line.
solid answer
~50 sThe choice is about blast radius and visibility. An inline `#checkov:skip=` is the narrowest exemption available — one block, one check id — and it lives at the violating line, so it appears in the diff of the change that needed it and dies with the resource. A `skip-check` entry in `.checkov.yaml`, or `--skip-check` on the command line, turns that rule off for **everything the scan covers**, with nothing at any violating site to indicate it, so a violation added next year silently inherits the exemption. `skip-path` is wider still: it removes whole directories from the scan, dropping every check over that code. Its honest use is code that is not deployed infrastructure — a module's `examples/` directory and its test fixtures. Put the exemption as close to the exempted thing as you can, and use the config file only for "not this rule here" or "not real infrastructure".
code
yaml · 8 lines# .checkov.yaml
skip-check:
- CKV_AWS_1 # nothing here records why, or who decided
skip-path:
- ".*/examples/.*"
- ".*/test/fixtures/.*"
...go deeper
Know that there is more than one way to stop a finding, and that a comment in the file affects one resource while an entry in the scan configuration affects everything the scan covers.
Be ready to rank the three mechanisms by blast radius and explain the visibility difference. Name the legitimate use of a path exclusion: fixtures and examples that are never deployed.
Show judgment about the config skip-check list as an artifact — it is an unowned rewrite of policy. Talk about the prospective nature of a rule-wide skip and how you would keep that list from growing.
Own the question of where exemption authority sits: what a team may self-serve inline versus what has to be a deliberate, written decision about a control. Be able to defend either answer against the delivery cost.
## Three levers, three blast radii A scanner gives you more than one way to stop a finding, and they are not interchangeable. Ranked from narrowest to widest: | Mechanism | Scope | Visible where the violation is? | Dies when? | |---|---|---|---| | Inline `#checkov:skip=ID:reason` | one block, one check | yes — it is at the line | the resource is deleted | | `skip-check: [ID]` in config / `--skip-check` | that check, across the whole scan | no | someone edits the config | | `skip-path: [pattern]` in config / `--skip-path` | every check, across matching paths | no | someone edits the config | The first column is what most people compare. The second column is what actually decides most reviews. ## Why visibility dominates An inline annotation is a piece of code. It arrives in a pull request, sits next to the thing it excuses, and is read by whoever reviews that file. Six months later, an engineer opening the resource sees immediately that a control was disabled here and why someone thought that was fine. A `skip-check` entry has none of that. The Terraform looks clean. The scan is green. Nothing at the violating resource hints that a control was ever meant to apply. Worse, the exemption is *prospective*: it does not just excuse today's violation, it pre-approves every future one. A team disables a check once for a legacy resource, and two years later the same class of violation ships in new code with nobody noticing — because the gate is not looking. ## When the config file is right anyway There are two honest uses. **The rule genuinely does not apply to this scan.** If the check encodes a control that the organisation has consciously decided not to enforce for this class of repository, disabling it once in configuration is more truthful than a hundred inline skips repeating the same reason. The test is whether you would be comfortable writing the justification once, in a place a reviewer will find it — the config file should carry a comment saying why, because the mechanism itself records nothing. **The path is not deployed infrastructure.** A Terraform module ships an `examples/` directory and a set of test fixtures whose entire purpose is to be scanned by the module's own tests, or to demonstrate a minimal configuration. That code is never applied to a real account. Excluding it with `skip-path` is correct: the alternative is decorating fixtures with skip comments that then become the copy-paste source for skips in real code. The hazard with `skip-path` is that the patterns are matched as regular expressions against paths. A pattern written loosely enough to catch `modules/foo/examples/` can also catch a directory called `examples-prod` or, worse, swallow a whole `modules/` tree. Because an excluded path produces no finding **and** no skip record, the mistake is invisible in the output — you cannot spot it by reading the report, only by reading the pattern. ## The pattern to be suspicious of The common anti-pattern is a `skip-check` list that grew one id at a time, each added by whoever was blocked that afternoon, none of them carrying a reason because the file has no field for one. That list is a de facto rewrite of the policy, made by nobody in particular. If a check is being disabled everywhere, that is a decision that deserves an owner and a written rationale — not a line in a YAML list. One related distinction worth keeping clean: making the whole run non-blocking (Checkov's `--soft-fail`) is **not** a suppression. Nothing is exempted; every finding is still reported, the run just stops failing. It changes what the gate does with the answer, not what the answer is. ## How to answer this in an interview Say the ranking, then say the test: exemption as close to the exempted thing as possible; the config file only for "not this rule, ever, here" or "not real infrastructure". Then name the failure mode of each — a skip comment copy-pasted onward, and a config skip that silently pre-approves everything that comes later.
- Why is a config-file skip-check more dangerous than the same number of inline skips?Because it is prospective and invisible. An inline skip excuses one resource that exists today; a config skip excuses every violation of that check that anyone adds later, in any file, with nothing at those sites to show a control was ever meant to apply. Reviewers of future pull requests see clean code and a green scan.
- A colleague adds skip-path for a directory to get the build green. What do you ask?Whether that code is deployed. If it is fixtures or examples, excluding it is right and the pattern should be tight enough to match only that. If it is real infrastructure, the exclusion drops every check over it, not the one that failed — the finding they were fighting is now hidden along with everything else in that tree, and nothing in the report will say so.
- Does making the run non-blocking count as suppressing findings?No. A soft-fail run still evaluates and reports every finding; it simply stops returning a failing exit code. Nothing is exempted and nothing is hidden. It is a statement about what the gate does with the answer, which is a different decision from which findings are excused.
saying these in an interview costs you the question
- Treats an inline skip and a config skip-check as equivalent
- Adds a check id to the config list to unblock one resource
- Uses a path exclusion to hide a single failing check
- Does not notice that config skips excuse future violations too
- Writes a loose path regex that swallows real infrastructure
- Calls a non-blocking run a suppression