Skip to content

feat(r0040): add unexpected process arguments rule - #39

Merged
matthyx merged 6 commits into
mainfrom
add-r0040-unexpected-process-arguments
Jun 26, 2026
Merged

matthyx merged 6 commits into
mainfrom
add-r0040-unexpected-process-arguments

Conversation

@matthyx

@matthyx matthyx commented Jun 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds the OSS rule R0040 — Unexpected Process Arguments (pkg/rules/r0040-unexpected-process-arguments/: YAML + README + tests). R0040 fires when an allowed binary is exec'd with an argv vector that was never recorded for that path, consuming ap.was_executed_with_args over the ExecsByPath projection. Opened as a draft because the expression depends on the node-agent #805 engine, which this repo does not yet pin — see the blocker below.

Details

R0040 is the argument-level companion to R0001. Where R0001 fires when an unknown binary runs, R0040 fires when an allowed binary is exec'd with an argv vector that was never recorded for that path. It delegates argv comparison to storage's dynamicpathdetector.MatchExecArgs, stays silent on unknown paths (R0001's domain) and on any matching argv.

ap.was_executed(event.containerId, parse.get_exec_path(event.args, event.comm, event.exepath))
  && !ap.was_executed_with_args(event.containerId, parse.get_exec_path(event.args, event.comm, event.exepath), event.args)

⛔ Blocked on kubescape/node-agent#805 — needs a go.mod bump before CI can go green

The rule expression uses two CEL symbols that only exist on the node-agent #805 branch and are not in the versions this repo currently pins:

Symbol Provided by Pinned today
3-arg parse.get_exec_path(args, comm, exepath) node-agent #805 ❌ node-agent v0.3.98-…-4aefa6517e0a (Apr 27) lacks it
ap.was_executed_with_args(containerId, path, args) node-agent #805 ❌ same
dynamicpathdetector.MatchExecArgs / CompareExecArgs storage #322 ❌ storage v0.0.258 (need ≥ v0.0.278)

Before this can merge, go.mod must bump node-agent to a release carrying the #805 engine and storage to ≥ v0.0.278. I did not bump go.mod here because that release doesn't exist yet (#805 is unmerged) and I don't want to pin the library to an unmerged feature branch.

What passes today vs. what's blocked

Verified locally against the current pins:

  • ✅ make lint-projection — clean (profileDependency: 0 + profileDataRequired: execs: all).
  • ✅ scripts/check_readmes.sh pkg/rules — OK.
  • ✅ go vet ./pkg/rules/r0040-…/ — compiles (the test only uses APIs present at the pin).
  • ❌ go test ./pkg/rules/r0040-…/ — fails only on found no matching overload for 'parse.get_exec_path' applied to '(list(dyn), string, string)', i.e. precisely the missing #805 overload. Flips green once go.mod is bumped.

Design note for review

I kept the 3-arg get_exec_path form so R0040 stays byte-identical to the expression validated by node-agent #805's component test (Test_32_UnexpectedProcessArguments). This diverges from the sibling OSS rules here (R0001/R0007/R1001/R1004), which currently use the 2-arg form + an explicit event.exepath fallback. Plan: migrate those siblings to the 3-arg form in a separate PR (the same migration #805 carries); if we'd rather R0040 adopt the existing 2-arg idiom instead, say so and I'll rework the expression + tests.

Tags include context:container alongside context:kubernetes, matching R0001 (argv anomaly is meaningful at the container boundary, not only in Kubernetes). rules-crd.yaml is a generated artifact (make generate-rules-crd) and is left untouched.

Summary by CodeRabbit

  • New Features
    • Added rule R0040 to alert on unexpected command-line arguments for executables already approved in the learned profile.
  • Bug Fixes
    • Improved executable-path resolution across multiple detections by preferring kernel-reported exepath and falling back when unavailable, reducing false positives.
    • Updated several exec and mount-related detections and refined /dev/shm detection behavior; also adjusted some rule matching semantics.
  • Documentation
    • Expanded/clarified “How It Works” documentation for updated exec/argument matching and /dev/shm logic.

Adds pkg/rules/r0040-unexpected-process-arguments/ (yaml + README + tests).
R0040 fires when an allowed binary is exec'd with an argv vector that was
never recorded for that path, consuming ap.was_executed_with_args over the
ExecsByPath projection surface and storage's dynamicpathdetector.MatchExecArgs.
It stays silent on unknown paths (R0001's domain) and on any recorded argv.

Blocked on node-agent#805: the expression uses the 3-arg
parse.get_exec_path(args, comm, exepath) overload and ap.was_executed_with_args,
neither of which exists in the pinned node-agent (v0.3.98-...-4aefa6517e0a) or
in storage v0.0.258. go.mod must bump node-agent to a release carrying the #805
engine and storage to >= v0.0.278 before `go test` can pass. lint-projection,
the README check, and `go vet` are green today; `go test` fails only on the
missing CEL overload.

Signed-off-by: matthyx <matthias.bertschy@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@matthyx matthyx added the ai-assisted Created through Armosec AI tooling (armosec-shared-rules plugin) label Jun 25, 2026
@coderabbitai

coderabbitai Bot commented Jun 25, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 861f8400-6d88-4c36-8c0a-095aed7c20cb

📥 Commits

Reviewing files that changed from the base of the PR and between 74b33e7 and 9cf22af.

📒 Files selected for processing (8)
  • pkg/rules/r0001-unexpected-process-launched/README.md
  • pkg/rules/r0001-unexpected-process-launched/unexpected-process-launched.yaml
  • pkg/rules/r0007-kubernetes-client-executed/README.md
  • pkg/rules/r0007-kubernetes-client-executed/kubernetes-client-executed.yaml
  • pkg/rules/r1001-exec-binary-not-in-base-image/README.md
  • pkg/rules/r1001-exec-binary-not-in-base-image/exec-binary-not-in-base-image.yaml
  • pkg/rules/r1004-exec-from-mount/exec-from-mount.yaml
  • rules-crd.yaml
✅ Files skipped from review due to trivial changes (1)
  • pkg/rules/r0007-kubernetes-client-executed/README.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/rules/r1001-exec-binary-not-in-base-image/README.md
  • pkg/rules/r0001-unexpected-process-launched/unexpected-process-launched.yaml
  • rules-crd.yaml

📝 Walkthrough

Walkthrough

The PR updates go.mod, adds a new R0040 rule for unexpected process arguments, and revises several existing rule expressions, catalog entries, and tests to use event.exepath-aware exec resolution or updated cache helpers.

Changes

Dependency Refresh

Layer / File(s) Summary
Module versions and replacements
go.mod
Direct requirements, indirect requirements, and replace directives are updated to newer module revisions.

Rule Updates

Layer / File(s) Summary
R0001 and R0007 exec path checks
pkg/rules/r0001-unexpected-process-launched/{README.md,unexpected-process-launched.yaml,rule_test.go}, pkg/rules/r0007-kubernetes-client-executed/{README.md,kubernetes-client-executed.yaml,rule_test.go}, rules-crd.yaml
R0001 and R0007 now use event.exepath-aware exec resolution in their exec-profile checks, and the tests use updated profile paths.
R1001 and R1004 exec path checks
pkg/rules/r1001-exec-binary-not-in-base-image/{README.md,exec-binary-not-in-base-image.yaml,rule_test.go}, pkg/rules/r1004-exec-from-mount/{README.md,exec-from-mount.yaml}, rules-crd.yaml
R1001 and R1004 now resolve exec paths with event.exepath precedence in their exec-profile checks, and the R1001 test table drops the container-mismatch case.
R0040 process argument rule
pkg/rules/r0040-unexpected-process-arguments/{README.md,unexpected-process-arguments.yaml,rule_test.go}, rules-crd.yaml
R0040 adds a rule manifest, README, tests, and a rules-crd entry for argv-mismatch detection; the same catalog block also updates R1000 wording.
R1000 /dev/shm detection
pkg/rules/r1000-exec-from-malicious-source/{README.md,exec-from-malicious-source.yaml}
R1000 changes the /dev/shm detection logic to use event.cwd and event.args[0], and updates the README description.
Rule catalog text updates
rules-crd.yaml
R1003, R1005, R1006, R1011, and R1015 rule entries update their names, messages, or descriptions.
Test cache accessors
pkg/rules/r0002-unexpected-file-access/rule_test.go, pkg/rules/r0003-unexpected-system-call/rule_test.go, pkg/rules/r0004-unexpected-capability-used/rule_test.go, pkg/rules/r0005-unexpected-domain-request/rule_test.go, pkg/rules/r0009-ebpf-program-load/rule_test.go, pkg/rules/r0010-unexpected-sensitive-file-access/rule_test.go, pkg/rules/r0011-unexpected-egress-network-traffic/rule_test.go, pkg/rules/r1003-malicious-ssh-connection/rule_test.go, pkg/rules/r1006-unshare-syscall/rule_test.go, pkg/rules/r1009-crypto-mining-related-port/rule_test.go, pkg/rules/r1010-symlink-created-over-sensitive-file/rule_test.go, pkg/rules/r1011-ld-preload-hook/rule_test.go, pkg/rules/r1012-hardlink-created-over-sensitive-file/rule_test.go, pkg/rules/r1030-unexpected-io_uring-operation/rule_test.go
Multiple rule tests now use GetApplicationProfile or GetNetworkNeighborhood helpers.
Projected profile validation
pkg/rules/r1011-ld-preload-hook/rule_test.go, pkg/rules/r1012-hardlink-created-over-sensitive-file/rule_test.go, pkg/rules/r1030-unexpected-io_uring-operation/rule_test.go
R1011, R1012, and R1030 tests pass ProjectedContainerProfile values into rule validation.

Sequence Diagram(s)

sequenceDiagram
  participant ExecveEvent
  participant CELEngine
  participant ApplicationProfile
  participant AlertOutput
  ExecveEvent->>CELEngine: evaluate R0040 with event.exepath and event.args
  CELEngine->>ApplicationProfile: ap.was_executed(resolved exec path)
  CELEngine->>ApplicationProfile: ap.was_executed_with_args(resolved exec path, event.args)
  ApplicationProfile-->>CELEngine: match / no match
  CELEngine->>AlertOutput: emit alert when path matches and argv pattern is new
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • kubescape/rulelibrary#32: Updates the same event.exepath exec-resolution path in R0001/R0007/R1001/R1004.
  • kubescape/rulelibrary#37: Renames and rewrites several rule entries that overlap with the R1000/R1003/R1006/R1011/R1015 catalog changes here.
  • kubescape/rulelibrary#38: Changes the R1005 fileless-execution message to reference memory-backed sources, matching the same rule text area touched here.

Suggested reviewers

  • amirmalka

Poem

I hopped through rules with a whisker twitch,
exepath paths and argv now switch.
R0040 nibbles noisy args just so,
And /dev/shm leaves a clearer glow.
🐇 Crunch, crunch—fresh carrots in the snow!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding the R0040 unexpected process arguments rule.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-r0040-unexpected-process-arguments

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 markdownlint-cli2 (0.22.1)
pkg/rules/r0001-unexpected-process-launched/README.md

markdownlint-cli2 wrapper config was not available before execution

pkg/rules/r0007-kubernetes-client-executed/README.md

markdownlint-cli2 wrapper config was not available before execution

pkg/rules/r1001-exec-binary-not-in-base-image/README.md

markdownlint-cli2 wrapper config was not available before execution


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

matthyx and others added 4 commits June 25, 2026 16:10
…igrate rule tests to new mock API

Pins node-agent to the pseudo-version of kubescape/node-agent#843
(feat(cel/parse): add 3-arg get_exec_path overload) so the R0040 rule
and its test can resolve parse.get_exec_path(args, comm, exepath). Also
bumps storage v0.0.258 -> v0.0.278 (MatchExecArgs / CompareExecArgs) and
aligns the replace block with node-agent main (inspektor-gadget fork,
runtime-spec v1.2.1, syft, stereoscope) so the module graph builds.

The node-agent bump (Apr -> Jun main) drifted the test-facing mock API;
migrates all rule tests accordingly:

  * objCache.ApplicationProfileCache().GetApplicationProfile(id)
      -> objCache.GetApplicationProfile(id)              (12 files)
  * objCache.NetworkNeighborhoodCache().GetNetworkNeighborhood(id)
      -> objCache.GetNetworkNeighborhood(id)             (4 files)
  * RulePolicyValidator.Validate(ruleId, comm, &profile.Spec.Containers[0])
      -> Validate(ruleId, comm, &objectcache.ProjectedContainerProfile{
             PolicyByRuleId: profile.Spec.Containers[0].PolicyByRuleId})
      (r1011, r1012, r1030 — Validate now takes a ProjectedContainerProfile)

Full suite, lint-projection, and the README check pass except one
pre-existing R1001 subtest (different_container_name), whose premise
(name-based profile isolation) the new RuleObjectCacheMock no longer
models — left for an owner decision; it is already covered by the
sibling "no application profile" case.

Signed-off-by: matthyx <matthias.bertschy@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ndant R1001 subtest

Aligns the sibling exec rules with the exepath-authoritative
parse.get_exec_path(args, comm, exepath) overload (node-agent#843),
matching the reviewed forms from node-agent#805's default-rules.yaml:

  R0001, R0007, R1001 — replace the 2-arg get_exec_path + the now-redundant
    (exepath == "" || !ap.was_executed(..., exepath)) fallback with the
    single 3-arg call. The overload subsumes the fallback: exepath wins
    (kernel-authoritative, spoof-resistant), argv[0] only when exepath is
    empty, then comm.
  R1004 — both get_exec_path call sites bumped to 3-arg; fallback dropped.
  R1000 (/dev/shm) — replace get_exec_path(...).startsWith('/dev/shm/')
    with a direct event.args[0] check and fix the clause grouping.

Test fixtures for R0001/R0007 now store the kernel-resolved exepath as the
profile Exec.Path (the recording side is exepath-authoritative), so the
"allowed" cases still suppress under the new resolution. READMEs updated
per the rule-yaml change.

Drops the redundant R1001 "different container name" subtest: its premise
(name-based profile isolation) is no longer modeled by RuleObjectCacheMock,
and the case it intended is already covered by the sibling "no application
profile" case.

Signed-off-by: matthyx <matthias.bertschy@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Regenerates the bundled CRD from pkg/rules/. Picks up the R0040 addition
and the 3-arg get_exec_path migration (R0001/R0007/R1000/R1001/R1004), plus
pre-existing source drift in rules whose per-rule yaml had been updated
without regenerating the CRD (R1003/R1005/R1006/R1011/R1015 name/description/
message). Generated artifact only — no source rule changes here.

Signed-off-by: matthyx <matthias.bertschy@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…o-version)

node-agent#843 (the 3-arg get_exec_path overload) merged and was released
as v0.3.147. Re-pins node-agent from the #843 branch pseudo-version to the
release tag; storage stays at v0.0.278. go test ./..., make lint-projection,
and the README check are green against the release.

Signed-off-by: matthyx <matthias.bertschy@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@matthyx
matthyx marked this pull request as ready for review June 26, 2026 05:56

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
pkg/rules/r0040-unexpected-process-arguments/README.md (1)

27-30: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Specify a language for the fenced code block.

markdownlint (MD040) flags this block. Since it's illustrative CEL, tag it as text (or cel) to silence the warning and aid rendering.

📝 Proposed fix
-```
+```text
 ap.was_executed(containerId, parse.get_exec_path(args, comm, exepath))
   && !ap.was_executed_with_args(containerId, parse.get_exec_path(args, comm, exepath), args)
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @pkg/rules/r0040-unexpected-process-arguments/README.md around lines 27 - 30,
The README’s fenced example in the r0040-unexpected-process-arguments
documentation is missing a language tag, triggering markdownlint MD040. Update
the code block in the rule documentation to specify a language such as text or
cel so the illustrative CEL snippet renders cleanly; target the fenced block
containing ap.was_executed and ap.was_executed_with_args.


</details>

<!-- cr-comment:v1:e1403672ea37b9fd84291e14 -->

_Source: Linters/SAST tools_

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @go.mod:

  • Line 162: The module is forcing github.com/opencontainers/runtime-spec to
    v1.2.1 via a replace directive even though primary dependencies like
    kubescape/node-agent and kubescape/storage require v1.3.0. Remove the
    runtime-spec replace override in go.mod so the resolver can select the required
    v1.3.0 version, and verify the resulting dependency graph still satisfies the
    imports used by the affected packages.
  • Line 61: The go.mod dependency on github.com/containerd/containerd is still
    pinned to a vulnerable indirect version, so update the module resolution to
    force a patched containerd release. Add a replace directive for
    github.com/containerd/containerd in go.mod to point to v1.7.33 or later, and
    keep the existing indirect requirement aligned so the module graph resolves to
    the safer version. Use the existing containerd/containerd entry in go.mod to
    locate the change.

In @rules-crd.yaml:

  • Around line 332-356: R0040 is enabled even though it depends on the
    unavailable ap.was_executed_with_args CEL helper, so update the rule definition
    for id R0040 to avoid runtime evaluation errors. Either set the enabled flag to
    false in the "Unexpected process arguments" entry, or only re-enable it after
    the pinned runtime includes the helper referenced in ruleExpression and
    description. Keep the existing ruleExpression and expressions intact; just gate
    activation until the dependency is present.
  • Line 21: The rule expressions are calling a 3-argument parse.get_exec_path
    overload that is not available in the pinned node-agent v0.3.147, so update each
    affected rule in rules-crd.yaml to use the supported 2-argument
    parse.get_exec_path(event.args, event.comm) form, or alternatively bump
    node-agent to a version that explicitly registers the 3-argument signature. Make
    the change consistently wherever parse.get_exec_path is used, and keep rule
    R0040 separate since it also depends on ap.was_executed_with_args.

Nitpick comments:
In @pkg/rules/r0040-unexpected-process-arguments/README.md:

  • Around line 27-30: The README’s fenced example in the
    r0040-unexpected-process-arguments documentation is missing a language tag,
    triggering markdownlint MD040. Update the code block in the rule documentation
    to specify a language such as text or cel so the illustrative CEL snippet
    renders cleanly; target the fenced block containing ap.was_executed and
    ap.was_executed_with_args.

</details>

<details>
<summary>🪄 Autofix (Beta)</summary>

Fix all unresolved CodeRabbit comments on this PR:

- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: defaults

**Review profile**: CHILL

**Plan**: Pro

**Run ID**: `344038c5-c2c5-488d-be0e-85e4d7f083fd`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 8faf6a99f9df0cc439466074d16c4ef344b4b3b3 and 74b33e772b2a9ada4e12aaccca9cda2978efe925.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `go.sum` is excluded by `!**/*.sum`

</details>

<details>
<summary>📒 Files selected for processing (32)</summary>

* `go.mod`
* `pkg/rules/r0001-unexpected-process-launched/README.md`
* `pkg/rules/r0001-unexpected-process-launched/rule_test.go`
* `pkg/rules/r0001-unexpected-process-launched/unexpected-process-launched.yaml`
* `pkg/rules/r0002-unexpected-file-access/rule_test.go`
* `pkg/rules/r0003-unexpected-system-call/rule_test.go`
* `pkg/rules/r0004-unexpected-capability-used/rule_test.go`
* `pkg/rules/r0005-unexpected-domain-request/rule_test.go`
* `pkg/rules/r0007-kubernetes-client-executed/README.md`
* `pkg/rules/r0007-kubernetes-client-executed/kubernetes-client-executed.yaml`
* `pkg/rules/r0007-kubernetes-client-executed/rule_test.go`
* `pkg/rules/r0009-ebpf-program-load/rule_test.go`
* `pkg/rules/r0010-unexpected-sensitive-file-access/rule_test.go`
* `pkg/rules/r0011-unexpected-egress-network-traffic/rule_test.go`
* `pkg/rules/r0040-unexpected-process-arguments/README.md`
* `pkg/rules/r0040-unexpected-process-arguments/rule_test.go`
* `pkg/rules/r0040-unexpected-process-arguments/unexpected-process-arguments.yaml`
* `pkg/rules/r1000-exec-from-malicious-source/README.md`
* `pkg/rules/r1000-exec-from-malicious-source/exec-from-malicious-source.yaml`
* `pkg/rules/r1001-exec-binary-not-in-base-image/README.md`
* `pkg/rules/r1001-exec-binary-not-in-base-image/exec-binary-not-in-base-image.yaml`
* `pkg/rules/r1001-exec-binary-not-in-base-image/rule_test.go`
* `pkg/rules/r1003-malicious-ssh-connection/rule_test.go`
* `pkg/rules/r1004-exec-from-mount/README.md`
* `pkg/rules/r1004-exec-from-mount/exec-from-mount.yaml`
* `pkg/rules/r1006-unshare-syscall/rule_test.go`
* `pkg/rules/r1009-crypto-mining-related-port/rule_test.go`
* `pkg/rules/r1010-symlink-created-over-sensitive-file/rule_test.go`
* `pkg/rules/r1011-ld-preload-hook/rule_test.go`
* `pkg/rules/r1012-hardlink-created-over-sensitive-file/rule_test.go`
* `pkg/rules/r1030-unexpected-io_uring-operation/rule_test.go`
* `rules-crd.yaml`

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* pkg/rules/r1001-exec-binary-not-in-base-image/rule_test.go

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread go.mod
github.com/cilium/ebpf v0.20.0 // indirect
github.com/containerd/cgroups/v3 v3.0.5 // indirect
github.com/containerd/cgroups/v3 v3.1.2 // indirect
github.com/containerd/containerd v1.7.30 // indirect

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if these vulnerabilities are addressable via newer versions or if they're constrained by upstream
# List available versions for containerd and docker
go list -m -versions github.com/containerd/containerd | head -5
go list -m -versions github.com/docker/docker | head -5
# Check if node-agent or storage have newer versions that bump these
go list -m -versions github.com/kubescape/node-agent | head -5
go list -m -versions github.com/kubescape/storage | head -5

Repository: kubescape/rulelibrary

Length of output: 11683


🏁 Script executed:

#!/bin/bash
# Check dependencies of newer node-agent and storage versions
# Use go mod graph to see what versions they depend on
go mod download github.com/kubescape/node-agent@v0.3.147 2>/dev/null || true
go mod download github.com/kubescape/storage@v0.0.278 2>/dev/null || true
go mod download github.com/kubescape/storage@v0.1.0 2>/dev/null || true
go mod download github.com/kubescape/storage@v0.2.0 2>/dev/null || true

# Check what containerd version node-agent v0.3.147 uses
go mod graph | grep -E "(node-agent.*containerd|storage.*containerd)" | head -20

Repository: kubescape/rulelibrary

Length of output: 1288


🏁 Script executed:

#!/bin/bash
# Check if containerd v1.7.33 fixes the mentioned vulnerabilities
# By checking containerd's security advisories or changelog
curl -s https://api.github.com/repos/containerd/containerd/releases | jq -r '.[] | select(.tag_name | test("v1\\.7\\.(3[0-9]|3[0-9]?)")) | {tag_name, name, body}' | head -100

Repository: kubescape/rulelibrary

Length of output: 228


🏁 Script executed:

#!/bin/bash
# Check the actual dependency tree in the current project
cat go.mod | grep -E "(containerd|docker)" -A 2 -B 2

Repository: kubescape/rulelibrary

Length of output: 1746


🏁 Script executed:

#!/bin/bash
# Check containerd release notes for security fixes in newer 1.7.x versions
curl -s "https://raw.githubusercontent.com/containerd/containerd/v1.7.33/CHANGELOG.md" | grep -A 50 "v1.7.31\|v1.7.32\|v1.7.33\|Security\|CVE" | head -100

Repository: kubescape/rulelibrary

Length of output: 159


🏁 Script executed:

#!/bin/bash
# Check what containerd version newer storage versions use
go mod download github.com/kubescape/storage@v0.1.0 2>/dev/null || true
go mod download github.com/kubescape/storage@v0.2.0 2>/dev/null || true
go mod graph | grep "storage.*containerd/containerd" || echo "No containerd/containerd dependency found in storage versions checked"
# Also check the actual go.mod of those versions if available
curl -s "https://raw.githubusercontent.com/kubescape/storage/v0.2.0/go.mod" | grep containerd
echo "---"
curl -s "https://raw.githubusercontent.com/kubescape/storage/v0.1.0/go.mod" | grep containerd

Repository: kubescape/rulelibrary

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check OSV database for specific CVEs related to containerd v1.7.30
# Search for HIGH severity vulnerabilities in containerd 1.7.x
python3 - <<'PY'
import urllib.request
import json

# Search OSV for containerd vulnerabilities
url = "https://api.osv.dev/v1/query"
data = json.dumps({
    "package": {
        "name": "github.com/containerd/containerd",
        "ecosystem": "Go"
    },
    "version": "1.7.30"
}).encode()

try:
    req = urllib.request.Request(url, data=data, headers={'Content-Type': 'application/json'})
    response = urllib.request.urlopen(req, timeout=10)
    result = json.loads(response.read())
    
    # Check severity and describe findings
    vulns = result.get('vulns', [])
    high_vulns = []
    for v in vulns:
        severity = v.get('severity', [])
        is_high = any(s.get('type') == 'CVSS_V3' and float(s.get('score', 0)) >= 7.0 for s in severity)
        if is_high or any('HIGH' in s.get('type', '') for s in severity):
            high_vulns.append({
                'id': v.get('id'),
                'summary': v.get('details', '')[:200],
                'severity': severity
            })
    
    print(f"Found {len(vulns)} total vulnerabilities")
    print(f"Found {len(high_vulns)} HIGH severity vulnerabilities:")
    for hv in high_vulns[:5]:
        print(f"  - {hv['id']}: {hv['summary']}")
except Exception as e:
    print(f"Error querying OSV: {e}")
PY

Repository: kubescape/rulelibrary

Length of output: 313


🏁 Script executed:

#!/bin/bash
# Query OSV using curl directly without Python SSL issues
curl -s -H "Content-Type: application/json" \
  --data-binary '{"package":{"name":"github.com/containerd/containerd","ecosystem":"Go"},"version":"1.7.30"}' \
  "https://api.osv.dev/v1/query" 2>/dev/null | head -1000

Repository: kubescape/rulelibrary

Length of output: 20976


🏁 Script executed:

#!/bin/bash
# Check containerd GitHub security advisories for HIGH severity issues in 1.7.x
curl -s "https://github.com/advisories?query=ecosystem%3Agolang+package%3Agithub.life-white.uk%2Fcontainerd%2Fcontainerd+version%3A1.7.30+severity%3Ahigh" 2>/dev/null | grep -i "cve\|advisory\|high" | head -50

Repository: kubescape/rulelibrary

Length of output: 15230


🏁 Script executed:

#!/bin/bash
# Check if containerd v1.7.31, v1.7.32, v1.7.33 have security patches
curl -s "https://api.github.com/repos/containerd/containerd/compare/v1.7.30...v1.7.33" 2>/dev/null | grep -i "security\|fix\|cve" | head -30

Repository: kubescape/rulelibrary

Length of output: 159


HIGH severity vulnerabilities in indirect containerd dependencies require replacement directive

OSV Scanner confirmed multiple HIGH severity vulnerabilities in containerd/containerd v1.7.30 used by node-agent v0.3.147:

  • runAsNonRoot bypass (CVE-2026-46680): Fixed in v1.7.32
  • Host-root command execution from image pull (CVE-2026-53488): Fixed in v1.7.33
  • CRI checkpoint CDI annotation smuggling (CVE-2026-53492): No fixed version in 1.7.x
  • CRI checkpoint local image tag poisoning (CVE-2026-50195): No fixed version in 1.7.x
  • Symlink following in CRI checkpoint restore (CVE-2026-53489): No fixed version in 1.7.x

While these libraries are consumed only for type/API access (not runtime orchestration), the vulnerabilities warrant mitigation.

Recommended actions:

  1. Add a replace directive to force the use of containerd/containerd v1.7.33 (or later) to immediately address the patchable vulnerabilities:

    replace github.com/containerd/containerd => github.com/containerd/containerd v1.7.33
    
  2. Track upstream releases of kubescape/node-agent for future updates that may bump the transitive dependency.

  3. Note that some critical CRI-related vulnerabilities have no fix in the 1.7.x series; consider monitoring containerd v2.x releases if upstream adopts them.

🧰 Tools
🪛 OSV Scanner (2.4.0)

[HIGH] 61-61: github.com/containerd/containerd 1.7.30: containerd CRI checkpoint restore CDI annotation smuggling in github.com/containerd/containerd

(GO-2026-5064)


[HIGH] 61-61: github.com/containerd/containerd 1.7.30: containerd: CRI checkpoint import allows local image tag poisoning in github.com/containerd/containerd

(GO-2026-5338)


[HIGH] 61-61: github.com/containerd/containerd 1.7.30: containerd user ID handling bypass allows runAsNonRoot evasion in github.com/containerd/containerd

(GO-2026-5378)


[HIGH] 61-61: github.com/containerd/containerd 1.7.30: containerd image-triggered runtime DoS via unbounded group parsing in github.com/containerd/containerd

(GO-2026-5475)


[HIGH] 61-61: github.com/containerd/containerd 1.7.30: Arbitrary host CRI log file read via symlink following in CRI checkpoint restore in github.com/containerd/containerd

(GO-2026-5622)


[HIGH] 61-61: github.com/containerd/containerd 1.7.30: containerd CRI — image-config LABEL flows to restart-monitor binary:// logger: host-root command execution from an image pull in github.com/containerd/containerd

(GO-2026-5758)


[HIGH] 61-61: github.com/containerd/containerd 1.7.30: containerd user ID handling bypass allows runAsNonRoot evasion

(GHSA-fqw6-gf59-qr4w)


[HIGH] 61-61: github.com/containerd/containerd 1.7.30: containerd image-triggered runtime DoS via unbounded group parsing

(GHSA-jpcc-p29g-p8mq)


[HIGH] 61-61: github.com/containerd/containerd 1.7.30: containerd CRI — image-config LABEL flows to restart-monitor binary:// logger: host-root command execution from an image pull

(GHSA-xhf5-7wjv-pqxp)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@go.mod` at line 61, The go.mod dependency on github.com/containerd/containerd
is still pinned to a vulnerable indirect version, so update the module
resolution to force a patched containerd release. Add a replace directive for
github.com/containerd/containerd in go.mod to point to v1.7.33 or later, and
keep the existing indirect requirement aligned so the module graph resolves to
the safer version. Use the existing containerd/containerd entry in go.mod to
locate the change.

Comment thread go.mod
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/opencontainers/runtime-spec v1.2.1 // indirect
github.com/opencontainers/runtime-spec v1.3.0 // indirect

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify runtime-spec replace compatibility
# Check which transitive dependency pulls in runtime-spec and if v1.2.1 satisfies it
go mod why -m github.com/opencontainers/runtime-spec
go mod graph | grep 'runtime-spec'

Repository: kubescape/rulelibrary

Length of output: 6243


Critical dependency conflict: runtime-spec v1.2.1 replace overrides v1.3.0 requirement from primary dependencies

The replace directive at line 280 forcing github.com/opencontainers/runtime-spec v1.2.1 directly conflicts with the explicit v1.3.0 requirements of github.com/kubescape/node-agent and github.com/kubescape/storage, which are core dependencies for this module.

Forcing v1.2.1 downgrades the API below what these primary dependencies expect, creating a high risk of build failures or runtime incompatibilities where v1.3.0 features or types are utilized.

Remove the replace directive for opencontainers/runtime-spec to allow the dependency resolver to select the required v1.3.0 version.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@go.mod` at line 162, The module is forcing
github.com/opencontainers/runtime-spec to v1.2.1 via a replace directive even
though primary dependencies like kubescape/node-agent and kubescape/storage
require v1.3.0. Remove the runtime-spec replace override in go.mod so the
resolver can select the required v1.3.0 version, and verify the resulting
dependency graph still satisfies the imports used by the affected packages.

Comment thread rules-crd.yaml Resolved
Comment thread rules-crd.yaml
Comment on lines +332 to +356
- name: "Unexpected process arguments"
enabled: true
id: "R0040"
description: "Detects an exec event whose path IS in the application profile but whose argv vector does not match any recorded argv pattern for that path. Consumes ap.was_executed_with_args, which walks the ExecsByPath projection surface and delegates argv comparison to dynamicpathdetector.MatchExecArgs (storage). Stays silent when the path is unknown (R0001 covers that case) and when the argv vector matches any recorded pattern (including the trailing zero-or-more form and the single-arg form); a '*' in a recorded arg is a literal character, not a wildcard."
expressions:
message: "'Unexpected process arguments: ' + event.comm + ' with PID ' + string(event.pid) + ' argv=' + event.args.map(a, string(a)).join(' ')"
uniqueId: "event.comm + '_' + event.exepath + '_' + event.args.map(a, string(a)).join(' ')"
ruleExpression:
- eventType: "exec"
expression: "ap.was_executed(event.containerId, parse.get_exec_path(event.args, event.comm, event.exepath)) && !ap.was_executed_with_args(event.containerId, parse.get_exec_path(event.args, event.comm, event.exepath), event.args)"
profileDependency: 0
profileDataRequired:
execs: all
severity: 3
supportPolicy: false
isTriggerAlert: true
mitreTactic: "TA0002"
mitreTechnique: "T1059"
tags:
- "context:kubernetes"
- "context:container"
- "anomaly"
- "process"
- "exec"
- "applicationprofile"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm was_executed_with_args is registered/available in the pinned deps
rg -nP "was_executed_with_args" -C2
fd -HI '^go\.mod$' --exec sh -c 'echo "== {} =="; grep -nE "node-agent|storage" {}'

Repository: kubescape/rulelibrary

Length of output: 159


Disable R0040 until ap.was_executed_with_args is available in the pinned runtime

The rule R0040 is set to enabled: true while depending on the CEL helper ap.was_executed_with_args. This helper requires storage updates from node-agent PR #805, which are not available in the currently pinned runtime versions. Enabling this rule without the helper registered in the CEL environment will cause rule evaluation errors in production.

  • Set enabled: true to enabled: false to prevent runtime errors until the dependency is resolved.
  • Alternatively, update the pinned runtime version to one that includes the was_executed_with_args helper before enabling the rule.
Current Rule State
      - name: "Unexpected process arguments"
        enabled: true  # ⚠️ Risk: Helper unavailable in target runtime
        id: "R0040"
        description: "Detects an exec event whose path IS in the application profile but whose argv vector does not match any recorded argv pattern for that path. Consumes ap.was_executed_with_args..."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rules-crd.yaml` around lines 332 - 356, R0040 is enabled even though it
depends on the unavailable ap.was_executed_with_args CEL helper, so update the
rule definition for id R0040 to avoid runtime evaluation errors. Either set the
enabled flag to false in the "Unexpected process arguments" entry, or only
re-enable it after the pinned runtime includes the helper referenced in
ruleExpression and description. Keep the existing ruleExpression and expressions
intact; just gate activation until the dependency is present.

…xec rules

Replaces the 3-arg parse.get_exec_path(args, comm, exepath) overload in
R0001/R0007/R1001/R1004 with a standard-CEL ternary:

  event.exepath != "" ? event.exepath : parse.get_exec_path(args, comm)

Behaviorally identical (exepath wins, else argv[0]/comm) but uses only the
2-arg overload + a ternary, both present on every agent version. So these
four rules no longer require node-agent v0.3.147 and need no
agentVersionRequirement gate or dual-variant: they keep working on older
agents and on the private-node-agent fork (which still imports
kubescape/node-agent v0.3.146) with the same spoof-resistant behavior.

R0040 is unchanged (it genuinely needs the 3-arg overload +
ap.was_executed_with_args from v0.3.147). READMEs and rules-crd.yaml
regenerated. go test ./..., lint-projection, and the README check pass.

Signed-off-by: matthyx <matthias.bertschy@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@matthyx
matthyx merged commit e2fe00e into main Jun 26, 2026
4 checks passed
@matthyx
matthyx deleted the add-r0040-unexpected-process-arguments branch June 26, 2026 10:02
@matthyx matthyx moved this to To Archive in KS PRs tracking Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-assisted Created through Armosec AI tooling (armosec-shared-rules plugin)

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

1 participant