> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pipefort.com/llms.txt
> Use this file to discover all available pages before exploring further.

# CICD-SEC-1 — Spoofable contains() membership check

> contains('literal', context) tests a string haystack for an attacker-influenceable needle.

| Field      | Value                                                                                                                                               |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| Category   | `CICD-SEC-1`                                                                                                                                        |
| Severity   | **MEDIUM**                                                                                                                                          |
| Confidence | MEDIUM                                                                                                                                              |
| Persona    | pedantic                                                                                                                                            |
| OWASP      | [CICD-SEC-1: Insufficient Flow Control](https://owasp.org/www-project-top-10-ci-cd-security-risks/CICD-SEC-01-Insufficient-Flow-Control-Mechanisms) |
| Auto-fix   | ✗                                                                                                                                                   |

## What the check does

Flags `contains('…literal…', <context>)` where the first argument is a literal
string haystack and the second is an attacker-influenceable context — a branch
ref, PR label, title, and so on.

## Why it matters

`contains(haystack, needle)` performs a **substring** test when the haystack is
a string. If the needle is attacker-controlled, a crafted value that happens to
be a substring of the haystack satisfies the check:

```yaml theme={null}
# ← a ref like "refs/heads/mai" (or "main-evil") satisfies the substring test
if: contains('refs/heads/main refs/heads/release', github.ref)
```

## Safe alternative

Test membership against an exact list, not a substring:

```yaml theme={null}
# array membership — exact match against each element
if: contains(fromJSON('["refs/heads/main","refs/heads/release"]'), github.ref)

# or an explicit comparison
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/release'
```
