Repository navigation
security(ci): the Kubescape guard's conditional inversion refuses six classes of legitimate step #3586
Description
🤖 Generated by the Agentic Engineer
The inversion's false-positive surface is much larger than I priced it
#3546 inverted the Kubescape guard's conditional screen from "recognise a scan" to "refuse unless shown scan-free". That closed nine bypass spellings. I priced its cost as "a conditional step mentioning the scan is refused" — small, and worth it.
That estimate was wrong. Review found six distinct classes of legitimate step the inversion refuses:
| # | Shape | Why it is refused |
|---|---|---|
| 1 | echo ok # ; "$STATUS" |
inline comments reach the command-position walk unstripped, so comment text is read as shell |
| 2 | a heredoc body | conditional scalars are screened line by line with no heredoc state, so data is read as code |
| 3 | { echo hello} |
an unquoted { grouping token looks like brace expansion, so the command name reads as undetermined |
| 4 | ARGS=( … "$VALUE" … ) |
a multi-line array assignment is inspected as a fresh command per line |
| 5 | checkov --file manifest.yaml --framework … |
--framework is not unique to KSail — checkov uses it, and this repository already guards checkov |
| 6 | bash -c 'echo scanner …' |
the shell-string rule substring-matches scan, so scanner matches |
Item 5 is the one that should have been obvious: the scalar-wide key is the inversion's main key, and it is not specific to the tool it is guarding.
Why this matters more than the count suggests
The repository's own hardening rule requires both halves of a change: what the security floor gained, and what the everyday path cost — and "a change that raises the floor and the friction is a draft, not a delivery". On that test the inversion currently fails. A guard that blocks comments, heredocs, brace groups, array assignments, and a second scanner is one people learn to route around, which costs more security than the nine spellings it closed.
Recommendation: split the work
The fixes on #3546 fall into two groups with very different risk:
- Surgical, no false-positive surface — the prefixed invocation, the shell-string form, backslash parity, word adjacency across a continuation, and separator splitting. Each closes a specific bypass by making the conditional screen read the shell the way the unconditional path already does. These are worth shipping as they are.
- The inversion and its command-position machinery — closes four further spellings (subshell, alias, path-qualified, non-bash shell) and carries the whole surface above.
Ship the first group; take the second as its own change where the surface can be worked properly — most likely by keying on something actually specific to the scan rather than --framework, and by giving the screen real comment/heredoc/brace state instead of a line-wise approximation.
Acceptance criteria
- All six shapes above are ACCEPTED.
- The nine bypass spellings closed on fix(ci): close the surgical Kubescape scan-guard bypasses, drop the inversion #3546 stay closed, or those that depend on the inversion move to this issue with their reproductions.
- The three real-workflow tests pass, and a control asserts the screen has not collapsed into "refuse every conditional step".
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Effort
Projects
- StatusShow more project fields✅ Done
Activity
fix(ci): avoid literal scan-word substring false positives
fix(ci): drop the conditional inversion, keep the surgical bypass clo…
devantler commentedon Sep 24, 2026
Status check against
main(35031dbb), found while working on Spike #3564.Criterion 1 is met. Since #3546, the guard accepts all six shapes in the table above in a conditional step. I ran each one beside the real scan.
Criterion 2 is not met yet. #3546 said the spellings that relied on the inversion would be tracked here with their reproductions, but they never reached this issue. Here they are, each run in a conditional (
if: always()) step beside the realnsa,mitrescan:mainnsa-only scan?(ksail workload scan --framework nsa)shopt -s expand_aliases,alias k=ksail,k workload scan --framework nsaon separate lines/usr/local/bin/ksail workload scan --framework nsashell: shThe same spellings in an unconditional step are refused on
main. So the alias and path-qualified spellings remain open after #3579; the parser-backed guard closes the subshell.Generated by Claude Code
chore: agent-claim #3586 nonce=0165dee5ebd88d7c378d8f992fcb0748
chore: agent-claim #3586 nonce=eb954866beccd6db1d4490dd3842c507
devantler commentedon Oct 3, 2026
Delivered by merged PR #4431, reviewed source commit 06d951f.
The shared ordinary-shell table accepts all six original legitimate shapes: inline comments, heredoc data, brace groups, multiline array assignments, the other framework-aware scanner, and harmless interpreter strings containing scanner prose. Existing bypass refusals remain covered by the same table used for both admission paths. The real workflows and positive conditional controls pass.
Acceptance was checked against the original issue body. All 266 test/subtest assertions passed with race detection, including 28 Bash recording witnesses. The original historical tests are unchanged; source CI and protected merge-queue CI passed. Closing as completed.