CRZ-013

Destructive workflow CRUD ops without confirmation/audit/MFA

low CVSS 3.1: 4.8 · Asset: admin.corezoid.com/api/2/json

Summary

During API op enumeration on /api/2/json, I confirmed that a single POST request with an authenticated session immediately deletes an entire workflow (conv object) with:

This was verified against tester-created workflows (obj_id 1835953, 1835954, 1835955, 1835956 — all created and deleted cleanly during the engagement as part of op-enumeration). The server responds simply with {"proc":"ok"} and the workflow is gone.

While conv_ttl: 0 in the Ansible config suggests deleted processes are kept in trash "forever" (recoverable via the restore op), the trash-retention doesn't mitigate:

Reproduction

# 1. Create a test workflow
curl -sk -b cookies.txt -X POST 'https://admin.corezoid.com/api/2/json' \
  -H 'Content-Type: application/json' \
  --data '{"ops":[{"type":"create","obj":"conv","title":"test","folder_id":0}]}'
# → {"proc":"ok","obj_id":1835953,...}

# 2. Single DELETE request — no confirmation required
curl -sk -b cookies.txt -X POST 'https://admin.corezoid.com/api/2/json' \
  -H 'Content-Type: application/json' \
  --data '{"ops":[{"type":"delete","obj":"conv","obj_id":1835953}]}'
# → {"proc":"ok","obj_id":1835953}

# 3. Verify gone
curl ... --data '{"ops":[{"type":"show","obj":"conv","obj_id":1835953}]}'
# → {"proc":"error","description":"bad object"}  (or similar)

Ops enumeration result (context)

The same endpoint also accepts these state-changing ops with no confirmation:

Op Object Effect
create conv creates new workflow (rate-limited per Erlang config)
delete conv deletes workflow (soft-delete to trash by default)
modify conv modifies workflow
restore conv restores from trash (reverses delete)

Impact scenarios

  1. Session hijack → business disruption. Any attacker who obtains admin session cookies (via phishing, subdomain XSS, stolen laptop) can issue a script that enumerates list conv and deletes every workflow. Trash retention means it's recoverable, but the service disruption during recovery could be hours-to-days and requires operator intervention.

  2. Insider ops risk. Developers or ops staff with admin access can accidentally delete production workflows (e.g., via a misconfigured CI script calling the API). No two-step confirmation makes fat-finger recovery harder.

  3. Batch operations via ops array. The /api/2/json endpoint accepts an array of ops in a single request. An attacker can pack dozens of deletes in one call: {"ops":[{"type":"delete","obj":"conv","obj_id":1},{"type":"delete",...},...]} — single HTTP request, mass deletion, no rate-limit interaction.

  4. CSRF-adjacent. The cookie duplication issue (CRZ-008) means on cross-site attacks that land a single POST with valid cookies, destructive ops complete atomically. The Lax-SameSite mw cookie alone is insufficient for /api/2/json (which requires both cookies), so the CSRF risk is lower here than on the GET endpoints — but any future bug that accepts the weaker auth would cascade into destructive capability.

Remediation

Priority 1 — confirmation token on destructive ops:

  1. Require a CSRF-style confirmation token obtained via a separate GET for each destructive op (or a signed short-lived token tied to the session + obj_id). Example:
    {"ops":[{"type":"delete","obj":"conv","obj_id":1835953,"confirm_token":"<signed-token>"}]}
  2. For web UI flows, show a confirmation modal on all delete actions.
  3. For batch deletes (more than 3 ops in a single request), require step-up auth (MFA re-prompt).

Priority 2 — audit trail:

  1. Emit an event to a tamper-evident audit log on every state-changing op: timestamp, user_id, remote_ip, op type, obj_id, obj_title, success/fail.
  2. Make audit logs read-only from the application level (write-once to a separate log bucket with immutability, like S3 Object Lock).
  3. Add "Activity" or "Audit" page in admin UI so users can see their own account's history.
  4. Alert on anomalous op volume (e.g., >50 deletes in <1 min from one session).

Priority 3 — defensive rate limits:

  1. The Erlang config capi.config.j2 mentions rate limits on create/modify/delete for conv|folder|dashboard — verify these actually fire (my probes didn't hit them, so either the limits are generous or not active).
  2. Per-object type: <10 deletes/minute, <100 modifies/minute by default.
  3. Tenant-level: no more than 10% of workflows deleted in 1 hour without an override.

Testing note

During this pentest I created 4 test workflows (IDs 1835953, 1835954, 1835955, 1835956 — all titled variants of "pentest-probe") and deleted each immediately after inspection. No residual test data was left in production. The engagement produced this finding as a side effect of trying to understand the API surface for sandbox-escape testing (which was not attempted — see out-of-scope notes in technical-report.md).

References