Benign, read-and-report enumeration agent onboarded via the Source Code path to answer the "does the sandbox hold?" questions from inside a running agent pod. Implements §4 of the security test plan.
Target for this engagement: console.agent-manager.cloud.wso2.com (ALPHA).
Report channel: controlled webhook (PROBE_WEBHOOK_URL). Runtime: portable bash.
The probe is enumeration, not a weapon. It:
- Only reads its own runtime context. No writes, no deletes, no process injection, no lateral movement.
- Masks all secret values. It reports names/paths/lengths and a short non-reversible fingerprint — never raw secrets. For the SA token it decodes only the non-secret JWT claims (namespace, audience, expiry), never the signature.
- Does not touch other tenants. Cross-tenant reach is inferred from the self-permission review and TCP connect checks only. It never enumerates or reads another tenant's objects.
- Fail-flag, not fail-forward. If self-review or reachability indicates cross-tenant access is possible, that is reported as a finding and escalation stops until the operator makes the call. (Per your instruction on this run.)
Everything above keeps the probe inside "authorized environment enumeration." Actual escape / lateral movement is a separate, explicitly-authorized step.
| Field(s) | Plan / ATT&CK link | Answers |
|---|---|---|
user, uid, gid, is_root, cap_eff, no_new_privs |
§C securityContext; T1611 | Root? Dangerous caps? no-new-privs on? |
base_image_osrelease, kernel |
§4 CVE mapping | Known-CVE surface for escape |
rootfs_root |
§C read-only FS | Is the root filesystem writable? |
mount_points, docker_sock_present, host_proc_mounted |
§C host mounts; T1611 | Escape primitives present? |
env_var_names, env_sensitive (masked) |
T1552.001 | Secrets injected via env? |
sa_token_present, sa_namespace, sa_token_claims, sa_token_masked |
T1552.001 / T1528 | SA token mounted? What identity/scope? |
self_rules_review* |
§C RBAC; T1069 | What can this pod's identity actually do? |
reach_metadata_80 |
§C metadata; T1552.005 | Cloud metadata endpoint reachable? |
reach_apiserver_443, reach_dns_53 |
§C kube-apiserver; T1046 | Control-plane reachable from pod? |
reach_egress_webhook |
§E exfil path | Does egress to internet work? |
All reachability checks are TCP connect only — no data is pulled from the metadata endpoint or the API server beyond the self-review introspection call.
| Var | Default | Purpose |
|---|---|---|
PROBE_WEBHOOK_URL |
(empty) | Controlled OOB endpoint to POST JSON to. Empty = stdout-only. |
PROBE_ID |
probe-$$ |
Label this run. Use probe-A / probe-B for the two-tenant test. |
PROBE_CONNECT_TIMEOUT |
3 |
Seconds per network check. |
PROBE_METADATA_IP |
169.254.169.254 |
Metadata IP (same for AWS/GCP/Azure link-local). |
PROBE_LINGER |
2 |
Seconds to stay alive before exit 0. |
Never hardcode the webhook URL in the repo — pass it as a deploy-time parameter/env so it isn't committed.
There is no repo descriptor file. Onboarding is a console form under Add Agent → Platform-Hosted Agent, with these fields:
| Field | Value for the probe |
|---|---|
| GitHub Repository | a repo you control containing the probe |
| Branch | main |
| App Path | subdir holding the probe |
| Language | Python (buildpack) or Dockerfile path |
| Start Command | python main.py (buildpack) |
| Port | 8000 |
| Interface | Chat Agent |
| Env vars | PROBE_WEBHOOK_URL=..., HOME=/tmp, PROBE_ID=probe-A |
Hard build constraint (verified): the build pipeline runs podman build,
then rejects any image whose USER is root ("Agent images are required to
run as non-root"). So a Dockerfile MUST declare a non-root user or the build fails.
Runtime constraints the probe must live within (verified from the SandboxTemplate):
- Runs as UID 65534 (nobody),
readOnlyRootFilesystem: true,allowPrivilegeEscalation: false, all capabilities dropped, seccompRuntimeDefault. Only/tmp,/data,/home/nobody/.cacheare writable. - Egress NetworkPolicy allows: DNS, the openchoreo data-plane / gateway namespaces, and public 443/80 only — with RFC1918 and 169.254.0.0/16 explicitly blocked. So: the webhook must be a public HTTPS endpoint, and the metadata-IP / apiserver connect checks are expected to fail if the policy is enforced (see §2a).
Option A — Dockerfile path (recommended for a bash probe):
FROM alpine:3.20
RUN apk add --no-cache bash curl
COPY probe.sh /probe.sh
RUN chmod +x /probe.sh
USER 65534
ENTRYPOINT ["/probe.sh"](The USER 65534 line is mandatory — without a non-root USER the build is rejected.)
Option B — Python buildpack path: commit a tiny main.py that
subprocess-execs probe.sh, set Language=Python, Start Command python main.py.
Buildpack images may not ship bash — prefer Option A for the shell probe.
Because the SandboxTemplate egress policy should block the metadata IP, RFC1918,
and the apiserver: if the probe reports reach_metadata_80: open,
reach_apiserver_443: open, or reach_dns_53 to an unexpected target, the
egress NetworkPolicy is not being enforced in this environment (CNI gap or
policy not applied) — a finding in itself. reach_egress_webhook: open to a
public HTTPS host is expected and confirms the probe path works.
Any endpoint you control that logs POST bodies. Options:
- A hosted request bin you own (paste the URL into
PROBE_WEBHOOK_URL). - A one-liner you run locally + a tunnel:
# minimal local receiver (prints each JSON report)
python3 -c 'from http.server import *; import sys
class H(BaseHTTPRequestHandler):
def do_POST(s):
n=int(s.headers.get("content-length",0)); print(s.rfile.read(n).decode()); s.send_response(200); s.end_headers()
HTTPServer(("0.0.0.0",8000),H).serve_forever()'Confirm reachability from the pod separately — if egress is blocked, the
reach_egress_webhook: closed field and the failed POST are themselves findings
(and you fall back to reading the report from platform/OTel logs, since the probe
also prints to stdout).
Deploy the same probe in tenant A (PROBE_ID=probe-A) and tenant B
(PROBE_ID=probe-B). Compare sa_namespace, self_rules_review, and
reachability. If B's identity can see/reach A's namespace or objects — stop and
flag it to me before any active cross-tenant request.
- Delete/undeploy both probe agents from the console.
- Revoke any tokens issued for the probe deployments.
- Rotate the webhook URL.
- Record what was deployed, when, and its removal in the engagement log.
probe.sh— the probe (syntax-checked, JSON-validated locally).README.md— this spec.