Skip to main content

Runtime Security Testing

Static analysis and dependency scanners check what code says. Some security issues only show up when the code runs: a query that becomes injectable once real input reaches it, an error page that leaks a stack trace, a new dependency that opens a connection to the internet when it's imported. Finding those takes a running target, and before merge there usually isn't one. Teams scan a shared staging environment after merge instead, where findings from many changes are mixed together and it's hard to tell which change caused which finding.

A Signadot sandbox gives every change its own running target. It deploys only the services the change touches, routes requests that carry its routing key to them, and serves everything else from the baseline. Point a security tool at the sandbox and every finding traces back to that one change, while the developer or coding agent that wrote it is still working on it.

This matters more as coding agents write more of the code. An agent can create a sandbox, run a scanner against it, read the report and fix what it finds, in the same loop it already uses for functional tests.

What you can catch before merge​

Runtime testing complements the static checks (SAST, dependency and image scanning) you already run in CI. It covers what they can't see:

Issue classExamplesHow it's detectedOpen source tools
InjectionSQL injection, OS command injection, path traversal, cross-site scriptingActive DAST against the sandboxed serviceZAP, Nuclei
Security misconfigurationMissing security headers, insecure cookie flags, verbose error pages and stack tracesPassive DASTZAP
Exposed endpoints and known CVEsDebug or admin routes left enabled, exposed config files, vulnerable framework versionsTemplate-based scanningNuclei
API input handlingServer errors on malformed input, responses that violate the schema, operations that don't enforce authenticationSchema-driven API fuzzingSchemathesis
Broken authorization between usersOne user or tenant reading or changing another's data (IDOR, BOLA)End-to-end tests that act as two identitiesYour testing framework
Risky runtime behaviorUnexpected outbound connections, shells spawned by the app, binaries written and run at runtimeRuntime threat detectionFalco, Tetragon
LLM and agent vulnerabilitiesPrompt injection, jailbreaks, an agent misusing its toolsAI red teamingpromptfoo, garak

How a security tool reaches a sandbox​

Which pattern to use depends on whether the tool sends requests or watches the workload.

Scanners in the cluster: run as a Signadot Job​

Package the scanner as a Signadot Job. The Job runs in a runner pod in your cluster, with the routing key of the target sandbox in the SIGNADOT_ROUTING_KEY environment variable. The scanner targets the in-cluster address of the baseline service, such as http://orders.shop.svc:8080, and adds the routing key to each request:

baggage: sd-routing-key=<routing key>

Requests with this header reach the sandboxed workload, and requests without it reach the baseline. If a scanner can't set its own headers, set trafficManager.injectRoutingKey: auto in the Job spec. A proxy next to the Job then adds the routing headers to all of its outbound plain HTTP and gRPC traffic. It doesn't touch TLS traffic.

The scanner's report is uploaded as a Job artifact. Nothing is exposed outside the cluster, which makes this the right pattern for active scans.

Scanners outside the cluster: target a preview URL​

Hosted scanners, and scanners on a developer's machine, can target a sandbox's preview URL. The preview URL adds the routing key itself. The scanner only needs to send a Signadot API key in the signadot-api-key header. Use a key from a dedicated service account rather than a personal key.

Runtime sensors: match the sandbox's pod label​

Runtime detection tools watch system calls on each node instead of sending requests, so they can't see the routing key header. Instead, the Signadot Operator (v1.4.0 or later) labels every forked pod with signadot.com/sandbox-routing-key, set to the sandbox's routing key. Scope rules or alerts to that label. Then drive traffic through the sandbox with your existing tests, so the changed code paths actually run.

Keep active scans contained​

Passive scans and runtime sensors only observe. Active scans and fuzzers send attack payloads and write junk data. A sandbox only deploys the services that changed: the sandboxed workload receives the payloads, but its calls to baseline services and shared databases are real. Before you run an active scan against a sandbox:

  • Start passive. A passive scan or a set of runtime rules catches a lot and can't damage anything. Make active scans opt-in.
  • Scope the scan to the changed service. Point the scanner at the sandboxed service or its OpenAPI definition, not at a frontend that fans out to every baseline service.
  • Isolate the data it writes. Give the sandbox its own database or schema with a resource plugin or database branching, so injected rows never land in shared data.
  • Fork what the scan reaches. If the changed service writes to another service the scan will exercise, add that service to the sandbox too. When a change spans several sandboxes, scan them together through a route group.
  • Use a dedicated job runner group. A job runner group sets the image, security context and Kubernetes permissions its Jobs run with, and only Signadot admins can create one. Keep scanners in their own runner group, with no more permissions than the scan needs.

Set up this way, an agent or a CI pipeline can run aggressive tests on every change without touching the shared environment other teams depend on.

Run it in the agent loop and in CI​

The same Job spec serves coding agents and CI.

Coding agents. An agent creates a sandbox for its change through the Signadot MCP server or the CLI. Then it submits the scan Job with the CLI, downloads the report artifact, fixes what the report shows, and runs the scan again until it's clean. The PR goes up with the clean report as evidence. To make this routine, add it to the agent's instructions, for example in AGENTS.md or CLAUDE.md:

## Security checks

Before opening a PR that changes an HTTP handler in services/orders:

1. Create or update a Signadot sandbox for the change.
2. Run `signadot job submit -f .signadot/security/zap-api-scan.yaml --set sandbox=<sandbox> --set target=http://orders.shop.svc:8080 --attach`.
3. If the Job fails, download the report with
`signadot artifact download --job <job-name> /zap/wrk/zap-report.html`,
fix every High-risk finding, and re-run until the Job passes.

The Job spec in this example comes from the ZAP tutorial.

CI. The workflow that creates a sandbox for each pull request (see CI/CD integrations) submits the same Job with --attach. The Job fails when the scanner exits with a failure, which fails the PR check, and the report stays attached to the Job for reviewers.

Integration guides​

Other open source tools​

The same patterns work for any tool that can add a request header or filter by pod label:

ToolWhat it testsHow to target a sandbox
NucleiTemplate-based checks for exposed endpoints, misconfigurations and known CVEsRun as a Job and pass -H "baggage: sd-routing-key=$SIGNADOT_ROUTING_KEY"
SchemathesisProperty-based API fuzzing from an OpenAPI or GraphQL schemaRun as a Job and pass -H "baggage: sd-routing-key=$SIGNADOT_ROUTING_KEY"
TetragoneBPF runtime observability and enforcementSelect pods with the signadot.com/sandbox-routing-key label using podSelector in a TracingPolicy
promptfooRed teaming for LLM apps and agentsPoint its HTTP target at the preview URL with a signadot-api-key header, or run it as a Job with the routing header

Commercial DAST, IAST and runtime security products connect the same way: through a request header, a preview URL, or pod labels.