● Zion Boggan
repos/Cyclops V2/vault/00-doctrine/SEVERITY-GATE.md
zionboggan.com ↗
245 lines · markdown
History for this file →
1
# SEVERITY-GATE - The Hard Gate
2
 
3
This is the gate every candidate must pass before it can become a finding report. It encodes Zion's
4
P1 "holy-shit" impact taxonomy as **eight impact families**. For each family it states the **exact
5
oracle** that counts as PROVEN, and the **v1 overclaim traps** that do NOT count.
6
 
7
**The binding rule:**
8
 
9
> Cyclops MUST NOT open a finding report unless the candidate is on a *demonstrable path* to one of
10
> the eight families below, **and** the family's oracle has fired (per [[OPERATING-CORE#3-proof-labels-the-four-states-a-candidate-can-be-in|proof labels]]).
11
> Anything below this bar - hardening notes, missing headers, blind reachability, info leaks without
12
> impact - goes to the [[../04-cleared-axes/README|cleared-axes log]], **never** to a report.
13
 
14
"Demonstrable path" means: at SOURCE_CONFIRMED time you can name the endpoint of the chain and it is
15
one of these families. If the best honest endpoint is "attacker can read an object they shouldn't" -
16
that is not on this list, and you stop and log it.
17
 
18
---
19
 
20
## Family 1 - Remote Code Execution (the crown)
21
 
22
Covers: Unauth RCE, Pre-Auth RCE, Wormable RCE, RCE via Deserialization / File-Upload /
23
Template-Injection (SSTI) / Command-Injection / SQLi-to-RCE, Reverse Shell, Web Shell.
24
 
25
**PROVEN (oracle):** code we chose runs in the target process. The artifact is one of:
26
- A callback to our listener (`curl`/DNS/TCP) from the target host, fired by our payload.
27
- `id` / `uname -a` / `hostname` output returned through the exploit channel.
28
- A file we wrote to the target FS from inside the target process (`/tmp/cyclops-$RAND`).
29
- For wormable: the above **plus** a demonstrated propagation primitive (the same payload reaches the
30
  next host with no new auth).
31
 
32
**Does NOT count (v1 traps):**
33
- "The deserializer accepts our object" - until a gadget chain actually executes, this is
34
  SOURCE_CONFIRMED at best. *Reaching* `pickle.loads` / `yaml.load` / `ObjectInputStream` is a
35
  hypothesis; a popped shell is the finding.
36
- "SSTI: `{{7*7}}` reflected `49`" - that is template *evaluation*, not yet RCE. The finding is
37
  `{{ cycler.__init__.__globals__.os.popen('id') }}` (or the engine's equivalent gadget) returning
38
  command output. Expression eval alone goes no further than SOURCE_CONFIRMED.
39
- "The upload endpoint accepts a `.php`/`.jsp`" - until the shell is *reached and executes*, you have
40
  an upload, not RCE. Prove the webroot path is served and the handler runs.
41
- "Command string is built from user input" - concatenation is a hypothesis; you need the injected
42
  command's *output* or callback.
43
 
44
---
45
 
46
## Family 2 - Container / VM / Sandbox / Hypervisor Escape & Orchestrator Takeover
47
 
48
Covers: container breakout, VM/sandbox/hypervisor escape, Kubernetes / Docker-socket takeover,
49
kernel / bootloader / firmware compromise.
50
 
51
**PROVEN (oracle):**
52
- **Container/sandbox escape:** a read or write on the **host** filesystem or host process namespace
53
  from inside the container (e.g. our canary file at `/host-canary` created from the container; a
54
  process visible in the host PID namespace; reading the host's `/etc/shadow` via an escaped mount).
55
- **Docker-socket / K8s takeover:** scheduling a pod/container we control on a node we should not
56
  control, proven by command output from that node, **or** reading a cluster secret
57
  (`/var/run/secrets/kubernetes.io/serviceaccount/token`) that grants cross-namespace action we then
58
  demonstrate.
59
- **Hypervisor escape:** guest-to-host code execution proven by an artifact on the host.
60
- **Kernel/firmware:** a controlled kernel crash with attacker-controlled fault (ASan/KASAN/oops with
61
  our pattern in RIP/registers), or a privilege transition to ring-0 capability demonstrated.
62
 
63
**Does NOT count:**
64
- "We are root *inside* the container." That is the starting position, not an escape.
65
- "The container has `CAP_SYS_ADMIN` / a mounted socket." That is a misconfig *observation*; the
66
  finding is the demonstrated breakout using it.
67
- "Node-to-node lateral movement is theoretically possible." Demonstrate the second node or it is
68
  SOURCE_CONFIRMED.
69
 
70
---
71
 
72
## Family 3 - Cloud / Identity Account Takeover & Privilege Escalation
73
 
74
Covers: cloud (AWS/Azure/GCP) account takeover, IAM priv-esc to admin, cross-tenant / tenant-isolation
75
break, SSO/SAML/OAuth bypass + ATO.
76
 
77
**PROVEN (oracle):**
78
- **Cloud ATO:** credentials (access key, session token, service-account JSON) retrieved **and** used
79
  to perform an action we were not entitled to, proven by the API response (e.g.
80
  `sts:GetCallerIdentity` returning a role we hijacked, then a `s3:ListBucket` on a bucket we should
81
  not see - against *our own* canary resources where possible).
82
- **IAM priv-esc:** starting principal A, end as admin/role B, proven by an action only B can take.
83
- **Cross-tenant break:** reading or mutating **tenant B's** data while authenticated as **tenant A**
84
  - with both tenants being *our own* planted accounts holding canary data. The artifact is tenant
85
  A's session returning tenant B's canary.
86
- **SSO/SAML/OAuth bypass:** a forged/relayed assertion or bypassed check that logs us in as a
87
  *different* user (our second canary user), proven by that user's authenticated session.
88
 
89
**Does NOT count (the biggest v1 trap):**
90
- **"Injection reachable" ≠ "ATO completes."** A JWT with `alg:none` *accepted* by a debug endpoint
91
  is not ATO until you forge a token for a *privileged* user and perform a privileged action with it.
92
- "The OAuth `redirect_uri` allows an open redirect" - that is a redirect; ATO needs the *token/code*
93
  captured and exchanged for a session.
94
- "IDOR lets me read another user's profile" - cross-object read of low-value data is **not** a
95
  tenant-isolation break unless it crosses a tenant trust boundary into material data. Most IDOR is
96
  cleared-axes, not a finding. (This is the exact class v1 over-reported.)
97
- "SAML response is not signed-checked in this code branch" - prove the forged assertion yields a
98
  session; a missing check that some upstream guard catches is DISPROVEN.
99
 
100
---
101
 
102
## Family 4 - Secret / Key / Repo / Build-Pipeline Compromise
103
 
104
Covers: JWT signing key / API key / private key / production secret / CI-CD secret compromise;
105
source-repo / GitHub-org / Actions-runner / build-pipeline takeover.
106
 
107
**PROVEN (oracle):**
108
- **Secret exfil:** the actual secret value retrieved through the exploit channel (the signing key
109
  bytes, the live API key, the `.env` contents) - verified live where safe by a *minimal* benign use
110
  (e.g. the API key returns `200` on a `whoami`-style endpoint; the JWT key validates a token we sign).
111
- **Repo/org takeover:** a write we land on a repo/org we should not control - a commit/branch/tag we
112
  pushed to a protected target (against *our own* canary repo for replica proof), or a workflow we
113
  caused to run with elevated `GITHUB_TOKEN` permissions.
114
- **Actions-runner / pipeline takeover:** code execution on the runner proven by an artifact (callback
115
  from inside the CI job, or exfil of `secrets.*` / the `GITHUB_TOKEN` to our listener). See
116
  [[../01-archetypes/cicd-supplychain]].
117
 
118
**Does NOT count:**
119
- "This key *looks* like a secret in the JS bundle" - a string that matches a regex is a hypothesis.
120
  Prove it is live and grants access (minimal benign call), or it is cleared-axes.
121
- "The workflow uses `pull_request_target`" - that is a *risky pattern*; the finding is the actual
122
  secret/token exfil it enables. Prove the injection executes in the privileged context.
123
- "An expired / revoked / sandboxed test key." Dead keys are not findings.
124
 
125
---
126
 
127
## Family 5 - Supply-Chain & Dependency Compromise
128
 
129
Covers: supply-chain / dependency-confusion / registry / artifact / signing-key compromise.
130
 
131
**PROVEN (oracle):**
132
- **Dependency confusion:** a package *we* published to a public registry under an internal name is
133
  pulled and **executed** by the target's build/install (callback from the install/postinstall step,
134
  proven against our own replica build). The artifact is the callback, not the namespace being claimable.
135
- **Artifact/registry poisoning:** a malicious artifact we placed is consumed and run downstream,
136
  proven by execution in the consumer.
137
- **Signing-key compromise:** the signing key retrieved (Family 4 oracle) **and** a malicious artifact
138
  signed-and-accepted by a verifier we don't control.
139
 
140
**Does NOT count:**
141
- "This internal package name is unclaimed on npm/PyPI." Claimability is SOURCE_CONFIRMED. Publishing
142
  a benign canary package and observing the *target's pipeline pull and run it* is the finding - and
143
  only against in-scope / owned pipelines. **Never** squat a name a non-consenting third party builds.
144
- "The lockfile has a typo-squat-adjacent name." Adjacency is not consumption.
145
 
146
---
147
 
148
## Family 6 - Mass Data Exfil & Financial Impact
149
 
150
Covers: mass PII / DB / payment-data exfil; financial theft / payment bypass / balance manipulation;
151
ransomware / data-destruction paths.
152
 
153
**PROVEN (oracle):**
154
- **Mass exfil:** a query/endpoint returning bulk records across the authorization boundary, proven on
155
  a replica seeded with canary PII - the artifact is the bulk canary set returned to an unprivileged
156
  principal. (Live: prove the primitive with a `COUNT(*)` or a single canary row, never bulk-pull real
157
  user data.)
158
- **Financial:** a state transition that moves value - balance increased, a payment accepted at the
159
  wrong price, a refund issued without debit - proven by the post-state on a replica/canary account.
160
- **Data destruction/ransomware path:** a demonstrated unauthorized write/delete primitive on data we
161
  planted, with the destructive step proven on a canary only.
162
 
163
**Does NOT count:**
164
- "The endpoint *could* return many rows if the `WHERE` were dropped." Demonstrate it.
165
- "**Read DoS** / a slow query / a large response." A denial-of-service or resource-exhaustion read is
166
  **not** RCE and not exfil. (Explicit v1 trap: do not dress up a DoS as a critical.)
167
- "The price is set client-side." Client-side observation is a hypothesis; prove the server accepts
168
  the manipulated value and the order/state actually changes.
169
- "I can see *one* of my own orders." Not mass, not cross-boundary.
170
 
171
---
172
 
173
## Family 7 - SSRF / XXE / File-Access Chains to Critical
174
 
175
Covers: SSRF→metadata / →internal-admin / →RCE; XXE→file-read; arbitrary file read of secrets;
176
arbitrary file write→RCE; path-traversal→secrets.
177
 
178
**PROVEN (oracle):**
179
- **SSRF:** must terminate in impact, not just an outbound request. PROVEN = the metadata credential
180
  retrieved (`169.254.169.254/latest/...` token *captured*), **or** an internal-admin action performed
181
  via the SSRF, **or** SSRF→RCE chained to a Family-1 artifact. A bare OOB callback proves *blind
182
  SSRF reachability* - that is SOURCE_CONFIRMED, not a finding on its own (see trap below).
183
- **XXE / arbitrary file read:** the *contents* of a real secret file retrieved through the channel -
184
  our canary at `/etc/cyclops-canary` for replica proof, or a genuinely sensitive file
185
  (`/etc/passwd` is a demo, a signing key / `.env` is the impact) on a permitted target.
186
- **Arbitrary file write→RCE:** the write lands somewhere that executes (cron, webroot, a `.so`/
187
  `.pth`/startup path) and the execution fires a Family-1 artifact. The write alone is not the finding;
188
  the resulting execution is.
189
- **Path-traversal:** the traversal returns secret contents, per the file-read oracle.
190
 
191
**Does NOT count (the canonical v1 trap):**
192
- **"Blind SSRF confirmed by a DNS callback"** with nothing behind it. Per Zion's standing rule, never
193
  submit enumeration / blind SSRF standalone - prove the full impact chain (metadata cred, internal
194
  admin, or RCE). Blind callback → cleared-axes or keep-pulling, not a report.
195
- "Traversal reads `/etc/passwd`." `/etc/passwd` is a *demonstration of the primitive*, not impact by
196
  itself on a modern box. Pull a real secret to cross into a finding.
197
- "File write to a `/tmp` no one executes." A write with no execution sink is SOURCE_CONFIRMED.
198
 
199
---
200
 
201
## Family 8 - Exposed Critical Service & Trust-Infrastructure Compromise
202
 
203
Covers: the "exposed service" family - Jupyter / Redis / Mongo / Elasticsearch / Jenkins / Grafana /
204
K8s-dashboard / Prometheus / Terraform-state / env-var exposure; **and** trust-infra compromise:
205
MFA / password-reset / session-hijack / WAF bypass to a critical action; AD / domain-admin /
206
golden-ticket / NTLM-relay; DNS / registrar / subdomain / email / BGP / CA / TLS-key compromise.
207
 
208
**PROVEN (oracle):**
209
- **Exposed service:** not "the port is open" - the **unauthed privileged capability exercised**. For
210
  Jupyter, a notebook executing `os.system` (Family-1 artifact). For Redis, an unauthed write we then
211
  turn into RCE (module load / cron / authorized_keys) or a secret read. For Terraform-state, the
212
  *secrets inside the state* retrieved. For an exposed `.env`, the secret retrieved **and** minimally
213
  validated live. The artifact is the capability, not the banner.
214
- **Trust-infra:** the takeover demonstrated - a subdomain we now serve content on (dangling
215
  CNAME claimed against *our own* canary), a password-reset flow yielding a *different* user's session
216
  (our second canary user), an NTLM relay landing an authenticated action as the relayed principal,
217
  a golden ticket authenticating as a domain principal in our lab forest.
218
 
219
**Does NOT count:**
220
- "Redis/Mongo/ES is reachable without auth." Exposure is the start. The finding is the data read or
221
  the RCE landed. (Many "exposed service" reports are really just a port scan result - that is
222
  cleared-axes until the capability fires.)
223
- "Grafana is on the internet." Until you prove the unauthed read of a datasource secret or an
224
  exploit, it is an observation.
225
- "The reset token is predictable-looking." Predict it and take over the canary account, or it is
226
  SOURCE_CONFIRMED.
227
- "A WAF can be bypassed." A bypass that reaches a *non-impactful* endpoint is nothing; the bypass
228
  must reach a critical action that then fires another family's oracle.
229
 
230
---
231
 
232
## Gate decision procedure (run this on every candidate)
233
 
234
1. **Name the endpoint.** Honestly, what is the *best* impact at the end of this chain? Write it down.
235
2. **Map it to a family.** Is that endpoint one of Families 1-8? If no → [[../04-cleared-axes/README|cleared-axes]], stop.
236
3. **Identify the oracle.** What single artifact would prove it? If you cannot name an artifact, the
237
   candidate is not yet SOURCE_CONFIRMED - it is a guess.
238
4. **Check it is novel, not a sibling-CVE.** Run the [[../06-methods/NOVELTY-DOCTRINE|novelty check]]
239
   *before* deep work.
240
5. **Drive the oracle on a replica.** Artifact → REPLICA_CONFIRMED. No artifact → DISPROVEN + log.
241
6. **Only now** may a report exist. And only if in scope may a LIVE_CANARY_CONFIRMED follow.
242
 
243
> If you find yourself writing a report whose impact section says "could", "may", "potentially",
244
> "an attacker might", or "this is likely exploitable" - you have failed the gate. Delete it and go
245
> get the artifact, or log it DISPROVEN.