Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions src/pentesting-ci-cd/pentesting-ci-cd-methodology.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,95 @@ Compromising a CI/CD pipeline or stealing credentials from it can let an attacke
- If a compromised package is suspected, inspect the published tarball and not only the Git repository, because the malicious loader/runtime may exist only in the published artifact.
- Hunt for unexpected package-manager execution inside CI such as `npm install` instead of `npm ci`, unexpected Bun downloads/execution, or new workflow artifacts generated from transient branches.

## GitOps / Argo CD attack surface

GitOps controllers are **deployment engines with cluster credentials** that continuously pull repositories, render manifests and push them into Kubernetes. Treat them as a mix of **CI runner + Kubernetes control-plane client**.

### High-value Argo CD targets

From a compromised pod or internal network segment, enumerate Argo CD components before focusing only on the public API/UI:

```bash
kubectl get pods,svc,endpoints -A | grep -i argocd
nc -vz <argocd-repo-server> 8081
nc -vz <argocd-redis> 6379
```

Interesting internal services:

- **`argocd-repo-server`**: clones repositories, runs Helm/Kustomize/plugins, and returns rendered manifests.
- **Redis**: stores cached manifest responses and Git reference metadata that may later drive deployments.

### Direct internal-service abuse

Do not assume the front-end API is the only reachable attack surface. If an **internal gRPC service** trusts requests because they are "normally" forwarded by the main API server, **direct access to that internal endpoint can bypass authz/authn entirely**. In Argo CD, this is especially interesting for manifest-generation RPCs because they accept repository and rendering parameters that are more dangerous than the normal user-facing workflow suggests.

Practical checks:

- Look for exposed/internal-only services on unusual ports such as **repo-server gRPC on TCP 8081**.
- Test whether the service answers gRPC/HTTP2 requests even when the public API enforces authentication.
- Compare what fields the **internal request object** accepts vs what the UI/public API normally exposes.
- Remember that Argo CD itself documents **repo-server gRPC as an internal API**, so any unexpected client access to it should be treated as suspicious.

### Kustomize-to-RCE primitive

If the target can be coerced into cloning an **attacker-controlled repository** and then running **`kustomize build`** with attacker-controlled build flags, the Helm integration can become an execution primitive:

```bash
kustomize build <attacker_repo_path> --enable-helm --helm-command ./payload.sh
```

Requirements:

- The service must fetch **attacker-controlled repository contents** first.
- The repository must contain a `kustomization.yaml` that actually triggers Helm processing, for example:

```yaml
helmCharts:
- name: pwn
version: 0.0.1
```

- The payload referenced by `--helm-command` must exist in the cloned repository and be executable.

This is useful because execution happens **relative to the downloaded repo**, so `./payload.sh` resolves to attacker-controlled code without needing shell metacharacter injection.

### Post-exploitation: secret theft and cache poisoning

After obtaining code execution inside a GitOps worker/repo-server pod:

- Dump **environment secrets** first (`env`, `/proc/1/environ`, mounted secrets). In Argo CD, the Redis password can be enough for the next stage.
- Check Redis for **gzip-compressed JSON cache entries** related to generated manifests and Git refs.
- In Argo CD, the most interesting keys are usually:
- **`mfst|...`** → cached rendered manifests
- **`git-refs|...`** → branch/ref to commit mappings

A useful GitOps persistence/deployment trick is to **poison both**:

1. Append a malicious manifest to the cached **`mfst|...`** entry for the target app/revision.
2. Modify the related **`git-refs|...`** mapping so Auto Sync believes the branch moved away and then back to the cached revision.

This can make the controller **apply attacker-controlled cached manifests** even when the attacker cannot directly modify the source repository.

### Detection / hardening notes

Useful defensive checks during an assessment or review:

- Verify **NetworkPolicies** isolate repo-server and Redis from arbitrary pods. In Helm-based installs, review whether per-component network policies are still left at their default **`*.networkPolicy.create=false`** values.
- Hunt for unexpected requests to manifest-generation RPCs and unusual Kustomize flags such as **`--enable-helm`** or **`--helm-command`**.
- Review Redis access for non-Argo CD pods and unexpected writes to **`mfst|`** / **`git-refs|`** keys.
- If Prometheus is enabled, inspect **repo-server metrics** and Redis metrics for unusual request spikes, especially requests initiated by **`argocd-repo-server`** or **`argocd-server`** outside expected deployment windows.

### Static-analysis tip: model typed API requests in CodeQL

For large Go services, default CodeQL remote sources may stop at raw HTTP bodies and miss flows that become obvious only after unmarshalling. When the codebase follows a repeated API shape such as:

- receiver type **`Server`** / **`Service`**
- first parameter **`context.Context`**
- second parameter = typed request object

you can model **`Parameter[1]`** as a remote source in a custom **`sourceModel`** pack and add **`os/exec`** arguments as **`command-injection`** sinks. This is a practical way to surface framework-specific paths from gRPC/REST request structs into dangerous helpers such as **`exec.Command(...)`**.

## More relevant info

### Tools & CIS Benchmark
Expand All @@ -130,6 +219,13 @@ Check this interesting article about the top 10 CI/CD risks according to Cider:
- [https://www.cidersecurity.io/blog/research/ppe-poisoned-pipeline-execution/?utm_source=github\&utm_medium=github_page\&utm_campaign=ci%2fcd%20goat_060422](https://www.cidersecurity.io/blog/research/ppe-poisoned-pipeline-execution/?utm_source=github&utm_medium=github_page&utm_campaign=ci%2fcd%20goat_060422)
- [The npm Threat Landscape: Attack Surface and Mitigations](https://unit42.paloaltonetworks.com/monitoring-npm-supply-chain-attacks/)
- [Checkmarx Security Update: April 22, 2026](https://checkmarx.com/blog/checkmarx-security-update-april-22/?p=108469)
- [Synacktiv - Caught in the Octopus Trap: Unauthenticated RCE in Argo CD with CodeQL](https://synacktiv.com/en/publications/caught-in-the-octopus-trap-unauthenticated-rce-in-argo-cd-with-codeql.html)
- [Argo CD docs - High Availability](https://argo-cd.readthedocs.io/en/stable/operator-manual/high_availability/)
- [Argo CD - repo-server NetworkPolicy manifest](https://github.com/argoproj/argo-cd/blob/master/manifests/base/repo-server/argocd-repo-server-network-policy.yaml)
- [Kustomize - Helm chart generator example](https://github.com/kubernetes-sigs/kustomize/blob/master/examples/chart.md)
- [Argo CD docs - repo-server command reference](https://argo-cd.readthedocs.io/en/stable/operator-manual/server-commands/argocd-repo-server/)
- [Argo CD docs - metrics](https://argo-cd.readthedocs.io/en/latest/operator-manual/metrics/)
- [Argo Helm - chart values reference](https://github.com/argoproj/argo-helm/blob/main/charts/argo-cd/README.md)


{{#include ../banners/hacktricks-training.md}}
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ sudo nc -nlvp 443

The scheduled task executes the payload, achieving SYSTEM-level privileges.

{{#include ../../../banners/hacktricks-training.md}}



### `Microsoft.Automation/automationAccounts/python3Packages/write`, `Microsoft.Automation/automationAccounts/runbooks/write`, `Microsoft.Automation/automationAccounts/runbooks/publish/action`, `Microsoft.Automation/automationAccounts/jobs/write`
Expand Down Expand Up @@ -601,3 +601,4 @@ az rest --method GET \
--url "https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.Automation/automationAccounts/${AUTOMATION_ACCOUNT}/jobs/${JOB_ID}/streams?api-version=2023-11-01"
```

{{#include ../../../banners/hacktricks-training.md}}