Skip to content

feat(golang): add /rasp/cmdi endpoint + enable CMDi RASP tests on net-http-orchestrion#7251

Draft
eliottness wants to merge 1 commit into
mainfrom
eliottness/cmdi-rasp
Draft

feat(golang): add /rasp/cmdi endpoint + enable CMDi RASP tests on net-http-orchestrion#7251
eliottness wants to merge 1 commit into
mainfrom
eliottness/cmdi-rasp

Conversation

@eliottness

@eliottness eliottness commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Motivation

Enable end-to-end system-tests coverage for the new dd-trace-go Command Injection (CMDi) RASP feature (exec variant, server.sys.exec.cmd). Companion PR: DataDog/dd-trace-go#4978.

Changes

  • Add a CMDI shared handler in utils/build/docker/golang/app/_shared/rasp/rasp.go with array-capable request parsing (GET query, urlencoded, JSON {"command":[...]}, XML <command><cmd>…</cmd></command>) and appsec.MonitorParsedHTTPBody. It runs the command via an instrumented os/exec path (no shell) so the WAF evaluates server.sys.exec.cmd.
  • Register /rasp/cmdi in the Go RASP weblogs: net-http-orchestrion, net-http, chi, gin, echo.
  • Enable the endpoint-dependent Test_Cmdi_* classes for net-http-orchestrion in manifests/golang.yml ("*": irrelevant, net-http-orchestrion: v2.11.0-dev); test_shi.py stays irrelevant.

Workflow

  1. ⚠️ Create your PR as draft ⚠️
  2. Work on you PR until the CI passes
  3. Mark it as ready for review

🛟 #apm-shared-testing 🛟

Reviewer checklist

  • Anything but tests/ or manifests/ is modified ? I have the approval from R&P team
  • A docker base image is modified?
    • the relevant build-XXX-image label is present
  • A scenario is added, removed or renamed?

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

CODEOWNERS have been resolved as:

manifests/golang.yml                                                    @DataDog/dd-trace-go-guild
utils/build/docker/golang/app/_shared/rasp/rasp.go                      @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/chi/main.go                               @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/echo/main.go                              @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/gin/main.go                               @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/net-http-orchestrion/main.go              @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/net-http/main.go                          @DataDog/dd-trace-go-guild @DataDog/system-tests-core

@datadog-datadog-us1-prod

datadog-datadog-us1-prod Bot commented Jul 2, 2026

Copy link
Copy Markdown

Pipelines  Tests

Fix all issues with BitsAI

⚠️ Warnings

🚦 4 Pipeline jobs failed

Testing the test | System Tests (golang, dev) / End-to-end #7 / net-http-orchestrion 7   View in Datadog   GitHub Actions

🧪 1 Test failed

tests.appsec.rasp.test_cmdi.Test_Cmdi_Capability.test_cmdi_capability[net-http-orchestrion] from system_tests_suite   View in Datadog
AssertionError: Capability ASM_RASP_CMDI not found

self = &lt;tests.appsec.rasp.test_cmdi.Test_Cmdi_Capability object at 0x7fc981ac3c80&gt;

    def test_cmdi_capability(self):
&gt;       interfaces.library.assert_rc_capability(Capabilities.ASM_RASP_CMDI)

tests/appsec/rasp/test_cmdi.py:271: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

...

Testing the test | System Tests (golang, dev) / End-to-end #18 / net-http-orchestrion 18   View in Datadog   GitHub Actions

🧪 8 Tests failed

tests.appsec.rasp.test_cmdi.Test_Cmdi_BodyJson.test_cmdi_post_json[net-http-orchestrion] from system_tests_suite   View in Datadog
AssertionError: assert 200 == 403
 &#43;  where 200 = HttpResponse(status_code:200, headers:{&#39;Date&#39;: &#39;Thu, 02 Jul 2026 15:55:35 GMT&#39;, &#39;Content-Length&#39;: &#39;0&#39;}, text:).status_code
 &#43;    where HttpResponse(status_code:200, headers:{&#39;Date&#39;: &#39;Thu, 02 Jul 2026 15:55:35 GMT&#39;, &#39;Content-Length&#39;: &#39;0&#39;}, text:) = &lt;tests.appsec.rasp.test_cmdi.Test_Cmdi_BodyJson object at 0x7f29af786510&gt;.r

self = &lt;tests.appsec.rasp.test_cmdi.Test_Cmdi_BodyJson object at 0x7f29af786510&gt;

    def test_cmdi_post_json(self):
&gt;       assert self.r.status_code == 403
E       AssertionError: assert 200 == 403
E        &#43;  where 200 = HttpResponse(status_code:200, headers:{&#39;Date&#39;: &#39;Thu, 02 Jul 2026 15:55:35 GMT&#39;, &#39;Content-Length&#39;: &#39;0&#39;}, text:).status_code
...
tests.appsec.rasp.test_cmdi.Test_Cmdi_BodyUrlEncoded.test_cmdi_post_urlencoded[net-http-orchestrion] from system_tests_suite   View in Datadog
AssertionError: assert 200 == 403
 &#43;  where 200 = HttpResponse(status_code:200, headers:{&#39;Date&#39;: &#39;Thu, 02 Jul 2026 15:55:35 GMT&#39;, &#39;Content-Length&#39;: &#39;0&#39;}, text:).status_code
 &#43;    where HttpResponse(status_code:200, headers:{&#39;Date&#39;: &#39;Thu, 02 Jul 2026 15:55:35 GMT&#39;, &#39;Content-Length&#39;: &#39;0&#39;}, text:) = &lt;tests.appsec.rasp.test_cmdi.Test_Cmdi_BodyUrlEncoded object at 0x7f29af98c4a0&gt;.r

self = &lt;tests.appsec.rasp.test_cmdi.Test_Cmdi_BodyUrlEncoded object at 0x7f29af98c4a0&gt;

    def test_cmdi_post_urlencoded(self):
&gt;       assert self.r.status_code == 403
E       AssertionError: assert 200 == 403
E        &#43;  where 200 = HttpResponse(status_code:200, headers:{&#39;Date&#39;: &#39;Thu, 02 Jul 2026 15:55:35 GMT&#39;, &#39;Content-Length&#39;: &#39;0&#39;}, text:).status_code
...
View all 8 test failures

Testing the test | System Tests (golang, dev) / End-to-end #12 / net-http-orchestrion 12   View in Datadog   GitHub Actions

View all 4 failed jobs.

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: e29ce50 | Docs | Datadog PR Page | Give us feedback!

…-http-orchestrion

Add the CMDI shared handler with array-capable request parsing (query/JSON/XML/urlencoded)
and appsec.MonitorParsedHTTPBody, register /rasp/cmdi in the Go RASP weblogs
(net-http-orchestrion, net-http, chi, gin, echo), and enable the Test_Cmdi_* classes
for net-http-orchestrion in manifests/golang.yml. Exec runs via an instrumented
os/exec path so the WAF evaluates server.sys.exec.cmd; no shell is used.
@eliottness

Copy link
Copy Markdown
Contributor Author

Cross-branch validation (dd-trace-go eliottness/command-injection + system-tests eliottness/cmdi-rasp): https://github.com/DataDog/dd-trace-go/actions/runs/28603975175

gh-worker-dd-mergequeue-cf854d Bot pushed a commit to DataDog/dd-trace-go that referenced this pull request Jul 6, 2026
…4978)

### What does this PR do?

Adds **Command Injection (CMDi) RASP** to the tracer, wired end-to-end at the single `os.StartProcess` choke point (which underlies every `os/exec` call) and active under Orchestrion. When the WAF detects a command-injection attempt (rule `rasp-932-110`, address `server.sys.exec.cmd`), `os.StartProcess` is blocked: it returns a `BlockingSecurityEvent` error and `(nil, err)` instead of launching the process. This mirrors the existing LFI feature.

- **emitter**: `RunCommandOperation`/`Args`/`Res` in `instrumentation/appsec/emitter/ossec` (no `os` import; generic).
- **listener**: `NewExecSecFeature` (activates on `server.sys.exec.cmd`), registered in `internal/appsec/features.go`. Forces `argv[0] = name` so the WAF evaluates the real executable per [RFC-0989] (defeats an `argv[0]`-spoofing bypass on raw `os.StartProcess`).
- **contrib/os**: context-aware `StartProcess` wrapper (named returns, argv forwarded unchanged).
- **orchestrion**: `os.StartProcess` aspect in `contrib/os/orchestrion.yml`.
- **remoteconfig**: advertise `ASM_RASP_CMDI` capability under `orchestrion.Enabled()`.
- **tests**: `contrib/os` unit tests (mock wrapper + table-driven real-WAF `cmdi_detector` vectors mirroring libddwaf) + orchestrion integration test (real WAF, HTTP 403) + testdata `rasp-932-110`.
- **ci**: run `APPSEC_RASP`, `APPSEC_RASP_NON_BLOCKING`, and `REMOTE_CONFIG_MOCKED_BACKEND_ASM_DD` on `net-http-orchestrion`.
- **docs**: appsec README + orchestrion.yml meta.

No spans, no shell variant, no `go-libddwaf` change.

### Motivation

Exploit prevention for command injection ([RFC-0989]). The shipped WAF ruleset already contains the command-injection rule and the tracer already has the `server.sys.exec.cmd` address/metrics/rule-type plumbing, so this is a wiring-plus-tests change.

Companion system-tests PR (adds the `/rasp/cmdi` weblog endpoint and enables `Test_Cmdi_*` for `net-http-orchestrion`): **DataDog/system-tests#7251**. The CMDi `net-http-orchestrion` `APPSEC_RASP` run goes green once that endpoint/manifest is available; a manual cross-branch `workflow_dispatch` run validating both branches together will be linked below.

### Reviewer's Checklist

- [ ] Changed code has unit tests for its functionality at or near 100% coverage.
- [ ] [System-Tests](https://github.com/DataDog/system-tests/) covering this feature have been added and enabled with the va.b.c-dev version tag.
- [ ] There is a benchmark for any new code, or changes to existing code.
- [ ] If this interacts with the agent in a new way, a system test has been added.
- [ ] New code is free of linting errors. You can check this by running `make lint` locally.
- [ ] New code doesn't break existing tests. You can check this by running `make test` locally.
- [ ] Add an appropriate team label so this PR gets put in the right place for the release notes.
- [ ] All generated files are up to date. You can check this by running `make generate` locally.
- [ ] Non-trivial go.mod changes reviewed by @DataDog/dd-trace-go-guild.

[RFC-0989]: internal exploit-prevention command-injection RFC


Co-authored-by: eliott.bouhana <eliott.bouhana@datadoghq.com>
eliottness added a commit to DataDog/dd-trace-go that referenced this pull request Jul 6, 2026
…4978)

### What does this PR do?

Adds **Command Injection (CMDi) RASP** to the tracer, wired end-to-end at the single `os.StartProcess` choke point (which underlies every `os/exec` call) and active under Orchestrion. When the WAF detects a command-injection attempt (rule `rasp-932-110`, address `server.sys.exec.cmd`), `os.StartProcess` is blocked: it returns a `BlockingSecurityEvent` error and `(nil, err)` instead of launching the process. This mirrors the existing LFI feature.

- **emitter**: `RunCommandOperation`/`Args`/`Res` in `instrumentation/appsec/emitter/ossec` (no `os` import; generic).
- **listener**: `NewExecSecFeature` (activates on `server.sys.exec.cmd`), registered in `internal/appsec/features.go`. Forces `argv[0] = name` so the WAF evaluates the real executable per [RFC-0989] (defeats an `argv[0]`-spoofing bypass on raw `os.StartProcess`).
- **contrib/os**: context-aware `StartProcess` wrapper (named returns, argv forwarded unchanged).
- **orchestrion**: `os.StartProcess` aspect in `contrib/os/orchestrion.yml`.
- **remoteconfig**: advertise `ASM_RASP_CMDI` capability under `orchestrion.Enabled()`.
- **tests**: `contrib/os` unit tests (mock wrapper + table-driven real-WAF `cmdi_detector` vectors mirroring libddwaf) + orchestrion integration test (real WAF, HTTP 403) + testdata `rasp-932-110`.
- **ci**: run `APPSEC_RASP`, `APPSEC_RASP_NON_BLOCKING`, and `REMOTE_CONFIG_MOCKED_BACKEND_ASM_DD` on `net-http-orchestrion`.
- **docs**: appsec README + orchestrion.yml meta.

No spans, no shell variant, no `go-libddwaf` change.

### Motivation

Exploit prevention for command injection ([RFC-0989]). The shipped WAF ruleset already contains the command-injection rule and the tracer already has the `server.sys.exec.cmd` address/metrics/rule-type plumbing, so this is a wiring-plus-tests change.

Companion system-tests PR (adds the `/rasp/cmdi` weblog endpoint and enables `Test_Cmdi_*` for `net-http-orchestrion`): **DataDog/system-tests#7251**. The CMDi `net-http-orchestrion` `APPSEC_RASP` run goes green once that endpoint/manifest is available; a manual cross-branch `workflow_dispatch` run validating both branches together will be linked below.

### Reviewer's Checklist

- [ ] Changed code has unit tests for its functionality at or near 100% coverage.
- [ ] [System-Tests](https://github.com/DataDog/system-tests/) covering this feature have been added and enabled with the va.b.c-dev version tag.
- [ ] There is a benchmark for any new code, or changes to existing code.
- [ ] If this interacts with the agent in a new way, a system test has been added.
- [ ] New code is free of linting errors. You can check this by running `make lint` locally.
- [ ] New code doesn't break existing tests. You can check this by running `make test` locally.
- [ ] Add an appropriate team label so this PR gets put in the right place for the release notes.
- [ ] All generated files are up to date. You can check this by running `make generate` locally.
- [ ] Non-trivial go.mod changes reviewed by @DataDog/dd-trace-go-guild.

[RFC-0989]: internal exploit-prevention command-injection RFC


Co-authored-by: eliott.bouhana <eliott.bouhana@datadoghq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants